Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSybren A. Stüvel <sybren@stuvel.eu>2021-06-03 11:07:09 +0300
committerSybren A. Stüvel <sybren@stuvel.eu>2021-06-03 11:07:09 +0300
commit440208bbb3c3cdd842295a1a41ce272d4893ac53 (patch)
tree6886fdcf41e9e7ce2bb7d5d472b86dacfb39bd1a
parentc2acc4613ca6bb5549ae2fd572f724cc7de874cc (diff)
parentcdabac54c4fe7c6f8df125814442762aa539172b (diff)
Merge remote-tracking branch 'origin/master' into asset-browser-poselib
-rw-r--r--io_anim_nuke_chan/export_nuke_chan.py8
-rw-r--r--io_curve_svg/import_svg.py2
-rw-r--r--io_mesh_stl/__init__.py2
-rw-r--r--node_wrangler.py757
-rwxr-xr-x[-rw-r--r--]presets/pov/light/02_(5400K)_High_Noon_Sun.py4
-rwxr-xr-x[-rw-r--r--]presets/pov/light/03_(6000K)_Daylight_Window.py4
-rwxr-xr-x[-rw-r--r--]presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py4
-rwxr-xr-x[-rw-r--r--]presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py4
-rwxr-xr-x[-rw-r--r--]presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py4
-rwxr-xr-x[-rw-r--r--]presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py4
-rwxr-xr-x[-rw-r--r--]presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py4
-rwxr-xr-x[-rw-r--r--]presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py4
-rwxr-xr-x[-rw-r--r--]presets/pov/light/21_(2700K)_7W_OLED_Panel.py4
-rwxr-xr-x[-rw-r--r--]render_povray/__init__.py5743
-rwxr-xr-xrender_povray/base_ui.py307
-rwxr-xr-x[-rw-r--r--]render_povray/df3_library.py (renamed from render_povray/df3.py)253
-rw-r--r--render_povray/nodes.py1369
-rwxr-xr-xrender_povray/object_curve_topology.py974
-rwxr-xr-xrender_povray/object_gui.py728
-rwxr-xr-xrender_povray/object_mesh_topology.py1540
-rwxr-xr-xrender_povray/object_particles.py255
-rwxr-xr-x[-rw-r--r--]render_povray/object_primitives.py (renamed from render_povray/primitives.py)1010
-rwxr-xr-xrender_povray/object_properties.py670
-rwxr-xr-x[-rw-r--r--]render_povray/render.py5552
-rwxr-xr-xrender_povray/render_gui.py546
-rwxr-xr-xrender_povray/render_properties.py687
-rwxr-xr-xrender_povray/scenography.py847
-rwxr-xr-xrender_povray/scenography_gui.py761
-rwxr-xr-xrender_povray/scenography_properties.py392
-rwxr-xr-xrender_povray/scripting.py529
-rwxr-xr-xrender_povray/scripting_gui.py268
-rwxr-xr-xrender_povray/scripting_properties.py57
-rwxr-xr-x[-rw-r--r--]render_povray/shading.py2719
-rwxr-xr-xrender_povray/shading_gui.py680
-rwxr-xr-xrender_povray/shading_nodes.py2011
-rwxr-xr-xrender_povray/shading_properties.py2290
-rwxr-xr-xrender_povray/texturing.py902
-rwxr-xr-xrender_povray/texturing_gui.py1251
-rwxr-xr-xrender_povray/texturing_properties.py1137
-rw-r--r--render_povray/ui.py4719
-rwxr-xr-x[-rw-r--r--]render_povray/update_files.py196
-rw-r--r--rigify/ui.py107
-rw-r--r--sun_position/__init__.py4
-rw-r--r--sun_position/hdr.py15
-rw-r--r--sun_position/north.py4
45 files changed, 20073 insertions, 19255 deletions
diff --git a/io_anim_nuke_chan/export_nuke_chan.py b/io_anim_nuke_chan/export_nuke_chan.py
index d1c9a9b4..9b5f6420 100644
--- a/io_anim_nuke_chan/export_nuke_chan.py
+++ b/io_anim_nuke_chan/export_nuke_chan.py
@@ -22,7 +22,7 @@
It takes the currently active object and writes it's transformation data
into a text file with .chan extension."""
-from mathutils import Matrix
+from mathutils import Matrix, Euler
from math import radians, degrees
@@ -39,6 +39,7 @@ def save_chan(context, filepath, y_up, rot_ord):
# prepare the correcting matrix
rot_mat = Matrix.Rotation(radians(-90.0), 4, 'X').to_4x4()
+ previous_rotation = Euler()
filehandle = open(filepath, 'w')
fw = filehandle.write
@@ -65,10 +66,13 @@ def save_chan(context, filepath, y_up, rot_ord):
fw("%f\t%f\t%f\t" % t[:])
# create rotation component
- r = mat.to_euler(rot_ord)
+ r = mat.to_euler(rot_ord, previous_rotation)
fw("%f\t%f\t%f\t" % (degrees(r[0]), degrees(r[1]), degrees(r[2])))
+ # store previous rotation for compatibility
+ previous_rotation = r
+
# if the selected object is a camera export vertical fov also
if camera:
vfov = degrees(camera.angle_y)
diff --git a/io_curve_svg/import_svg.py b/io_curve_svg/import_svg.py
index b2f42b57..b98aacbb 100644
--- a/io_curve_svg/import_svg.py
+++ b/io_curve_svg/import_svg.py
@@ -1390,6 +1390,8 @@ class SVGGeometryRECT(SVGGeometry):
ob = SVGCreateCurve(self._context)
cu = ob.data
+ id_names_from_node(self._node, ob)
+
if self._styles['useFill']:
cu.dimensions = '2D'
cu.fill_mode = 'BOTH'
diff --git a/io_mesh_stl/__init__.py b/io_mesh_stl/__init__.py
index 7af1c2d1..c367946a 100644
--- a/io_mesh_stl/__init__.py
+++ b/io_mesh_stl/__init__.py
@@ -139,7 +139,7 @@ class ImportSTL(Operator, ImportHelper):
bpy.ops.object.select_all(action='DESELECT')
for path in paths:
- objName = bpy.path.display_name(os.path.basename(path))
+ objName = bpy.path.display_name_from_filepath(path)
tris, tri_nors, pts = stl_utils.read_stl(path)
tri_nors = tri_nors if self.use_facet_normal else None
blender_utils.create_and_link_mesh(objName, tris, tri_nors, pts, global_matrix)
diff --git a/node_wrangler.py b/node_wrangler.py
index e9ba5e74..118408c4 100644
--- a/node_wrangler.py
+++ b/node_wrangler.py
@@ -19,8 +19,8 @@
bl_info = {
"name": "Node Wrangler",
"author": "Bartek Skorupa, Greg Zaal, Sebastian Koenig, Christian Brinkmann, Florian Meyer",
- "version": (3, 37),
- "blender": (2, 83, 0),
+ "version": (3, 38),
+ "blender": (2, 93, 0),
"location": "Node Editor Toolbar or Shift-W",
"description": "Various tools to enhance and speed up node-based workflow",
"warning": "",
@@ -43,6 +43,7 @@ from bpy.props import (
from bpy_extras.io_utils import ImportHelper, ExportHelper
from gpu_extras.batch import batch_for_shader
from mathutils import Vector
+from nodeitems_utils import node_categories_iter
from math import cos, sin, pi, hypot
from os import path
from glob import glob
@@ -54,7 +55,7 @@ from collections import namedtuple
#################
# rl_outputs:
# list of outputs of Input Render Layer
-# with attributes determinig if pass is used,
+# with attributes determining if pass is used,
# and MultiLayer EXR outputs names and corresponding render engines
#
# rl_outputs entry = (render_pass, rl_output_name, exr_output_name, in_eevee, in_cycles)
@@ -90,7 +91,7 @@ rl_outputs = (
# shader nodes
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
shaders_input_nodes_props = (
('ShaderNodeAmbientOcclusion', 'AMBIENT_OCCLUSION', 'Ambient Occlusion'),
('ShaderNodeAttribute', 'ATTRIBUTE', 'Attribute'),
@@ -115,7 +116,7 @@ shaders_input_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
shaders_output_nodes_props = (
('ShaderNodeOutputAOV', 'OUTPUT_AOV', 'AOV Output'),
('ShaderNodeOutputLight', 'OUTPUT_LIGHT', 'Light Output'),
@@ -124,7 +125,7 @@ shaders_output_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
shaders_shader_nodes_props = (
('ShaderNodeAddShader', 'ADD_SHADER', 'Add Shader'),
('ShaderNodeBsdfAnisotropic', 'BSDF_ANISOTROPIC', 'Anisotropic BSDF'),
@@ -149,7 +150,7 @@ shaders_shader_nodes_props = (
('ShaderNodeVolumeScatter', 'VOLUME_SCATTER', 'Volume Scatter'),
)
# (rna_type.identifier, type, rna_type.name)
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
shaders_texture_nodes_props = (
('ShaderNodeTexBrick', 'TEX_BRICK', 'Brick Texture'),
@@ -169,7 +170,7 @@ shaders_texture_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
shaders_color_nodes_props = (
('ShaderNodeBrightContrast', 'BRIGHTCONTRAST', 'Bright Contrast'),
('ShaderNodeGamma', 'GAMMA', 'Gamma'),
@@ -181,7 +182,7 @@ shaders_color_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
shaders_vector_nodes_props = (
('ShaderNodeBump', 'BUMP', 'Bump'),
('ShaderNodeDisplacement', 'DISPLACEMENT', 'Displacement'),
@@ -194,7 +195,7 @@ shaders_vector_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
shaders_converter_nodes_props = (
('ShaderNodeBlackbody', 'BLACKBODY', 'Blackbody'),
('ShaderNodeClamp', 'CLAMP', 'Clamp'),
@@ -213,7 +214,7 @@ shaders_converter_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
shaders_layout_nodes_props = (
('NodeFrame', 'FRAME', 'Frame'),
('NodeReroute', 'REROUTE', 'Reroute'),
@@ -222,7 +223,7 @@ shaders_layout_nodes_props = (
# compositing nodes
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
compo_input_nodes_props = (
('CompositorNodeBokehImage', 'BOKEHIMAGE', 'Bokeh Image'),
('CompositorNodeImage', 'IMAGE', 'Image'),
@@ -237,7 +238,7 @@ compo_input_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
compo_output_nodes_props = (
('CompositorNodeComposite', 'COMPOSITE', 'Composite'),
('CompositorNodeOutputFile', 'OUTPUT_FILE', 'File Output'),
@@ -247,7 +248,7 @@ compo_output_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
compo_color_nodes_props = (
('CompositorNodeAlphaOver', 'ALPHAOVER', 'Alpha Over'),
('CompositorNodeBrightContrast', 'BRIGHTCONTRAST', 'Bright/Contrast'),
@@ -264,7 +265,7 @@ compo_color_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
compo_converter_nodes_props = (
('CompositorNodePremulKey', 'PREMULKEY', 'Alpha Convert'),
('CompositorNodeValToRGB', 'VALTORGB', 'ColorRamp'),
@@ -284,7 +285,7 @@ compo_converter_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
compo_filter_nodes_props = (
('CompositorNodeBilateralblur', 'BILATERALBLUR', 'Bilateral Blur'),
('CompositorNodeBlur', 'BLUR', 'Blur'),
@@ -303,7 +304,7 @@ compo_filter_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
compo_vector_nodes_props = (
('CompositorNodeMapRange', 'MAP_RANGE', 'Map Range'),
('CompositorNodeMapValue', 'MAP_VALUE', 'Map Value'),
@@ -313,7 +314,7 @@ compo_vector_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
compo_matte_nodes_props = (
('CompositorNodeBoxMask', 'BOXMASK', 'Box Mask'),
('CompositorNodeChannelMatte', 'CHANNEL_MATTE', 'Channel Key'),
@@ -331,7 +332,7 @@ compo_matte_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
compo_distort_nodes_props = (
('CompositorNodeCornerPin', 'CORNERPIN', 'Corner Pin'),
('CompositorNodeCrop', 'CROP', 'Crop'),
@@ -349,7 +350,7 @@ compo_distort_nodes_props = (
)
# (rna_type.identifier, type, rna_type.name)
# Keeping mixed case to avoid having to translate entries when adding new nodes in operators.
-# Keeping things in alphabetical orde so we don't need to sort later.
+# Keeping things in alphabetical order so we don't need to sort later.
compo_layout_nodes_props = (
('NodeFrame', 'FRAME', 'Frame'),
('NodeReroute', 'REROUTE', 'Reroute'),
@@ -529,7 +530,7 @@ operations = [
('COSH', 'Hyperbolic Cosine', 'Hyperbolic Cosine Mode'),
('TANH', 'Hyperbolic Tangent', 'Hyperbolic Tangent Mode'),
('POWER', 'Power', 'Power Mode'),
- ('LOGARITHM', 'Logatithm', 'Logarithm Mode'),
+ ('LOGARITHM', 'Logarithm', 'Logarithm Mode'),
('SQRT', 'Square Root', 'Square Root Mode'),
('INVERSE_SQRT', 'Inverse Square Root', 'Inverse Square Root Mode'),
('EXPONENT', 'Exponent', 'Exponent Mode'),
@@ -555,6 +556,14 @@ operations = [
('DEGREES', 'To Degrees', 'To Degrees Mode'),
]
+# Operations used by the geometry boolean node and join geometry node
+geo_combine_operations = [
+ ('JOIN', 'Join Geometry', 'Join Geometry Mode'),
+ ('INTERSECT', 'Intersect', 'Intersect Mode'),
+ ('UNION', 'Union', 'Union Mode'),
+ ('DIFFERENCE', 'Difference', 'Difference Mode'),
+]
+
# in NWBatchChangeNodes additional types/operations. Can be used as 'items' for EnumProperty.
# used list, not tuple for easy merging with other lists.
navs = [
@@ -598,6 +607,11 @@ draw_color_sets = {
viewer_socket_name = "tmp_viewer"
+def get_nodes_from_category(category_name, context):
+ for category in node_categories_iter(context):
+ if category.name == category_name:
+ return sorted(category.items(context), key=lambda node: node.label)
+
def is_visible_socket(socket):
return not socket.hide and socket.enabled and socket.type != 'CUSTOM'
@@ -680,40 +694,41 @@ def node_mid_pt(node, axis):
def autolink(node1, node2, links):
link_made = False
-
- for outp in node1.outputs:
- for inp in node2.inputs:
+ available_inputs = [inp for inp in node2.inputs if inp.enabled]
+ available_outputs = [outp for outp in node1.outputs if outp.enabled]
+ for outp in available_outputs:
+ for inp in available_inputs:
if not inp.is_linked and inp.name == outp.name:
link_made = True
links.new(outp, inp)
return True
- for outp in node1.outputs:
- for inp in node2.inputs:
+ for outp in available_outputs:
+ for inp in available_inputs:
if not inp.is_linked and inp.type == outp.type:
link_made = True
links.new(outp, inp)
return True
# force some connection even if the type doesn't match
- for outp in node1.outputs:
- for inp in node2.inputs:
+ if available_outputs:
+ for inp in available_inputs:
if not inp.is_linked:
link_made = True
- links.new(outp, inp)
+ links.new(available_outputs[0], inp)
return True
# even if no sockets are open, force one of matching type
- for outp in node1.outputs:
- for inp in node2.inputs:
+ for outp in available_outputs:
+ for inp in available_inputs:
if inp.type == outp.type:
link_made = True
links.new(outp, inp)
return True
# do something!
- for outp in node1.outputs:
- for inp in node2.inputs:
+ for outp in available_outputs:
+ for inp in available_inputs:
link_made = True
links.new(outp, inp)
return True
@@ -1236,7 +1251,7 @@ class NWNodeWrangler(bpy.types.AddonPreferences):
def nw_check(context):
space = context.space_data
- valid_trees = ["ShaderNodeTree", "CompositorNodeTree", "TextureNodeTree"]
+ valid_trees = ["ShaderNodeTree", "CompositorNodeTree", "TextureNodeTree", "GeometryNodeTree"]
valid = False
if space.type == 'NODE_EDITOR' and space.node_tree is not None and space.tree_type in valid_trees:
@@ -1598,14 +1613,17 @@ class NWSwapLinks(Operator, NWBase):
# Swap Inputs
elif len(selected_nodes) == 1:
+ if n1.inputs and n1.inputs[0].is_multi_input:
+ self.report({'WARNING'}, "Can't swap inputs of a multi input socket!")
+ return {'FINISHED'}
if n1.inputs:
types = []
i=0
for i1 in n1.inputs:
- if i1.is_linked:
+ if i1.is_linked and not i1.is_multi_input:
similar_types = 0
for i2 in n1.inputs:
- if i1.type == i2.type and i2.is_linked:
+ if i1.type == i2.type and i2.is_linked and not i2.is_multi_input:
similar_types += 1
types.append ([i1, similar_types, i])
i += 1
@@ -1686,10 +1704,10 @@ class NWAddAttrNode(Operator, NWBase):
nodes.active.attribute_name = self.attr_name
return {'FINISHED'}
-class NWEmissionViewer(Operator, NWBase):
- bl_idname = "node.nw_emission_viewer"
- bl_label = "Emission Viewer"
- bl_description = "Connect active node to Emission Shader for shadeless previews"
+class NWPreviewNode(Operator, NWBase):
+ bl_idname = "node.nw_preview_node"
+ bl_label = "Preview Node"
+ bl_description = "Connect active node to Emission Shader for shadeless previews, or to the geometry node tree's output"
bl_options = {'REGISTER', 'UNDO'}
def __init__(self):
@@ -1701,7 +1719,7 @@ class NWEmissionViewer(Operator, NWBase):
def poll(cls, context):
if nw_check(context):
space = context.space_data
- if space.tree_type == 'ShaderNodeTree':
+ if space.tree_type == 'ShaderNodeTree' or space.tree_type == 'GeometryNodeTree':
if context.active_node:
if context.active_node.type != "OUTPUT_MATERIAL" or context.active_node.type != "OUTPUT_WORLD":
return True
@@ -1772,11 +1790,13 @@ class NWEmissionViewer(Operator, NWBase):
groupout.location.x = loc_x
groupout.location.y = loc_y
groupout.select = False
+ # So that we don't keep on adding new group outputs
+ groupout.is_active_output = True
return groupout
@classmethod
def search_sockets(cls, node, sockets, index=None):
- #recursevley scan nodes for viewer sockets and store in list
+ # recursively scan nodes for viewer sockets and store in list
for i, input_socket in enumerate(node.inputs):
if index and i != index:
continue
@@ -1855,6 +1875,98 @@ class NWEmissionViewer(Operator, NWBase):
nodes, links = active_tree.nodes, active_tree.links
base_node_tree = space.node_tree
active = nodes.active
+
+ # For geometry node trees we just connect to the group output,
+ # because there is no "viewer node" yet.
+ if space.tree_type == "GeometryNodeTree":
+ valid = False
+ if active:
+ for out in active.outputs:
+ if is_visible_socket(out):
+ valid = True
+ break
+ # Exit early
+ if not valid:
+ return {'FINISHED'}
+
+ delete_sockets = []
+
+ # Scan through all nodes in tree including nodes inside of groups to find viewer sockets
+ self.scan_nodes(base_node_tree, delete_sockets)
+
+ # Find (or create if needed) the output of this node tree
+ geometryoutput = self.ensure_group_output(base_node_tree)
+
+ # Analyze outputs, make links
+ out_i = None
+ valid_outputs = []
+ for i, out in enumerate(active.outputs):
+ if is_visible_socket(out) and out.type == 'GEOMETRY':
+ valid_outputs.append(i)
+ if valid_outputs:
+ out_i = valid_outputs[0] # Start index of node's outputs
+ for i, valid_i in enumerate(valid_outputs):
+ for out_link in active.outputs[valid_i].links:
+ if is_viewer_link(out_link, geometryoutput):
+ if nodes == base_node_tree.nodes or self.link_leads_to_used_socket(out_link):
+ if i < len(valid_outputs) - 1:
+ out_i = valid_outputs[i + 1]
+ else:
+ out_i = valid_outputs[0]
+
+ make_links = [] # store sockets for new links
+ delete_nodes = [] # store unused nodes to delete in the end
+ if active.outputs:
+ # If there is no 'GEOMETRY' output type - We can't preview the node
+ if out_i is None:
+ return {'FINISHED'}
+ socket_type = 'GEOMETRY'
+ # Find an input socket of the output of type geometry
+ geometryoutindex = None
+ for i,inp in enumerate(geometryoutput.inputs):
+ if inp.type == socket_type:
+ geometryoutindex = i
+ break
+ if geometryoutindex is None:
+ # Create geometry socket
+ geometryoutput.inputs.new(socket_type, 'Geometry')
+ geometryoutindex = len(geometryoutput.inputs) - 1
+
+ make_links.append((active.outputs[out_i], geometryoutput.inputs[geometryoutindex]))
+ output_socket = geometryoutput.inputs[geometryoutindex]
+ for li_from, li_to in make_links:
+ base_node_tree.links.new(li_from, li_to)
+ tree = base_node_tree
+ link_end = output_socket
+ while tree.nodes.active != active:
+ node = tree.nodes.active
+ index = self.ensure_viewer_socket(node,'NodeSocketGeometry', connect_socket=active.outputs[out_i] if node.node_tree.nodes.active == active else None)
+ link_start = node.outputs[index]
+ node_socket = node.node_tree.outputs[index]
+ if node_socket in delete_sockets:
+ delete_sockets.remove(node_socket)
+ tree.links.new(link_start, link_end)
+ # Iterate
+ link_end = self.ensure_group_output(node.node_tree).inputs[index]
+ tree = tree.nodes.active.node_tree
+ tree.links.new(active.outputs[out_i], link_end)
+
+ # Delete sockets
+ for socket in delete_sockets:
+ tree = socket.id_data
+ tree.outputs.remove(socket)
+
+ # Delete nodes
+ for tree, node in delete_nodes:
+ tree.nodes.remove(node)
+
+ nodes.active = active
+ active.select = True
+ force_update(context)
+ return {'FINISHED'}
+
+
+ # What follows is code for the shader editor
output_types = [x[1] for x in shaders_output_nodes_props]
valid = False
if active:
@@ -2021,11 +2133,22 @@ class NWFrameSelected(Operator, NWBase):
return {'FINISHED'}
-class NWReloadImages(Operator, NWBase):
+class NWReloadImages(Operator):
bl_idname = "node.nw_reload_images"
bl_label = "Reload Images"
bl_description = "Update all the image nodes to match their files on disk"
+ @classmethod
+ def poll(cls, context):
+ valid = False
+ if nw_check(context) and context.space_data.tree_type != 'GeometryNodeTree':
+ if context.active_node is not None:
+ for out in context.active_node.outputs:
+ if is_visible_socket(out):
+ valid = True
+ break
+ return valid
+
def execute(self, context):
nodes, links = get_nodes_links(context)
image_types = ["IMAGE", "TEX_IMAGE", "TEX_ENVIRONMENT", "TEXTURE"]
@@ -2094,9 +2217,16 @@ class NWSwitchNodeType(Operator, NWBase):
list(texture_layout_nodes_props)
)
+ geo_to_type: StringProperty(
+ name="Switch to type",
+ default = '',
+ )
+
def execute(self, context):
nodes, links = get_nodes_links(context)
to_type = self.to_type
+ if self.geo_to_type != '':
+ to_type = self.geo_to_type
# Those types of nodes will not swap.
src_excludes = ('NodeFrame')
# Those attributes of nodes will be copied if possible
@@ -2275,8 +2405,8 @@ class NWMergeNodes(Operator, NWBase):
mode: EnumProperty(
name="mode",
- description="All possible blend types and math operations",
- items=blend_types + [op for op in operations if op not in blend_types],
+ description="All possible blend types, boolean operations and math operations",
+ items= blend_types + [op for op in geo_combine_operations if op not in blend_types] + [op for op in operations if op not in blend_types],
)
merge_type: EnumProperty(
name="merge type",
@@ -2284,6 +2414,7 @@ class NWMergeNodes(Operator, NWBase):
items=(
('AUTO', 'Auto', 'Automatic Output Type Detection'),
('SHADER', 'Shader', 'Merge using ADD or MIX Shader'),
+ ('GEOMETRY', 'Geometry', 'Merge using Boolean or Join Geometry Node'),
('MIX', 'Mix Node', 'Merge using Mix Nodes'),
('MATH', 'Math Node', 'Merge using Math Nodes'),
('ZCOMBINE', 'Z-Combine Node', 'Merge using Z-Combine Nodes'),
@@ -2291,6 +2422,74 @@ class NWMergeNodes(Operator, NWBase):
),
)
+ # Check if the link connects to a node that is in selected_nodes
+ # If not, then check recursively for each link in the nodes outputs.
+ # If yes, return True. If the recursion stops without finding a node
+ # in selected_nodes, it returns False. The depth is used to prevent
+ # getting stuck in a loop because of an already present cycle.
+ @staticmethod
+ def link_creates_cycle(link, selected_nodes, depth=0)->bool:
+ if depth > 255:
+ # We're stuck in a cycle, but that cycle was already present,
+ # so we return False.
+ # NOTE: The number 255 is arbitrary, but seems to work well.
+ return False
+ node = link.to_node
+ if node in selected_nodes:
+ return True
+ if not node.outputs:
+ return False
+ for output in node.outputs:
+ if output.is_linked:
+ for olink in output.links:
+ if NWMergeNodes.link_creates_cycle(olink, selected_nodes, depth+1):
+ return True
+ # None of the outputs found a node in selected_nodes, so there is no cycle.
+ return False
+
+ # Merge the nodes in `nodes_list` with a node of type `node_name` that has a multi_input socket.
+ # The parameters `socket_indices` gives the indices of the node sockets in the order that they should
+ # be connected. The last one is assumed to be a multi input socket.
+ # For convenience the node is returned.
+ @staticmethod
+ def merge_with_multi_input(nodes_list, merge_position,do_hide, loc_x, links, nodes, node_name, socket_indices):
+ # The y-location of the last node
+ loc_y = nodes_list[-1][2]
+ if merge_position == 'CENTER':
+ # Average the y-location
+ for i in range(len(nodes_list)-1):
+ loc_y += nodes_list[i][2]
+ loc_y = loc_y/len(nodes_list)
+ new_node = nodes.new(node_name)
+ new_node.hide = do_hide
+ new_node.location.x = loc_x
+ new_node.location.y = loc_y
+ selected_nodes = [nodes[node_info[0]] for node_info in nodes_list]
+ prev_links = []
+ outputs_for_multi_input = []
+ for i,node in enumerate(selected_nodes):
+ node.select = False
+ # Search for the first node which had output links that do not create
+ # a cycle, which we can then reconnect afterwards.
+ if prev_links == [] and node.outputs[0].is_linked:
+ prev_links = [link for link in node.outputs[0].links if not NWMergeNodes.link_creates_cycle(link, selected_nodes)]
+ # Get the index of the socket, the last one is a multi input, and is thus used repeatedly
+ # To get the placement to look right we need to reverse the order in which we connect the
+ # outputs to the multi input socket.
+ if i < len(socket_indices) - 1:
+ ind = socket_indices[i]
+ links.new(node.outputs[0], new_node.inputs[ind])
+ else:
+ outputs_for_multi_input.insert(0, node.outputs[0])
+ if outputs_for_multi_input != []:
+ ind = socket_indices[-1]
+ for output in outputs_for_multi_input:
+ links.new(output, new_node.inputs[ind])
+ if prev_links != []:
+ for link in prev_links:
+ links.new(new_node.outputs[0], link.to_node.inputs[0])
+ return new_node
+
def execute(self, context):
settings = context.preferences.addons[__name__].preferences
merge_hide = settings.merge_hide
@@ -2305,6 +2504,8 @@ class NWMergeNodes(Operator, NWBase):
do_hide = True
tree_type = context.space_data.node_tree.type
+ if tree_type == 'GEOMETRY':
+ node_type = 'GeometryNode'
if tree_type == 'COMPOSITING':
node_type = 'CompositorNode'
elif tree_type == 'SHADER':
@@ -2320,9 +2521,16 @@ class NWMergeNodes(Operator, NWBase):
if (merge_type == 'ZCOMBINE' or merge_type == 'ALPHAOVER') and tree_type != 'COMPOSITING':
merge_type = 'MIX'
mode = 'MIX'
+ if (merge_type != 'MATH' and merge_type != 'GEOMETRY') and tree_type == 'GEOMETRY':
+ merge_type = 'AUTO'
+ # The math nodes used for geometry nodes are of type 'ShaderNode'
+ if merge_type == 'MATH' and tree_type == 'GEOMETRY':
+ node_type = 'ShaderNode'
selected_mix = [] # entry = [index, loc]
selected_shader = [] # entry = [index, loc]
+ selected_geometry = [] # entry = [index, loc]
selected_math = [] # entry = [index, loc]
+ selected_vector = [] # entry = [index, loc]
selected_z = [] # entry = [index, loc]
selected_alphaover = [] # entry = [index, loc]
@@ -2331,17 +2539,29 @@ class NWMergeNodes(Operator, NWBase):
if merge_type == 'AUTO':
for (type, types_list, dst) in (
('SHADER', ('MIX', 'ADD'), selected_shader),
+ ('GEOMETRY', [t[0] for t in geo_combine_operations], selected_geometry),
('RGBA', [t[0] for t in blend_types], selected_mix),
('VALUE', [t[0] for t in operations], selected_math),
+ ('VECTOR', [], selected_vector),
):
output_type = node.outputs[0].type
valid_mode = mode in types_list
+ # When mode is 'MIX' we have to cheat since the mix node is not used in
+ # geometry nodes.
+ if tree_type == 'GEOMETRY':
+ if mode == 'MIX':
+ if output_type == 'VALUE' and type == 'VALUE':
+ valid_mode = True
+ elif output_type == 'VECTOR' and type == 'VECTOR':
+ valid_mode = True
+ elif type == 'GEOMETRY':
+ valid_mode = True
# When mode is 'MIX' use mix node for both 'RGBA' and 'VALUE' output types.
# Cheat that output type is 'RGBA',
# and that 'MIX' exists in math operations list.
# This way when selected_mix list is analyzed:
# Node data will be appended even though it doesn't meet requirements.
- if output_type != 'SHADER' and mode == 'MIX':
+ elif output_type != 'SHADER' and mode == 'MIX':
output_type = 'RGBA'
valid_mode = True
if output_type == type and valid_mode:
@@ -2349,6 +2569,7 @@ class NWMergeNodes(Operator, NWBase):
else:
for (type, types_list, dst) in (
('SHADER', ('MIX', 'ADD'), selected_shader),
+ ('GEOMETRY', [t[0] for t in geo_combine_operations], selected_geometry),
('MIX', [t[0] for t in blend_types], selected_mix),
('MATH', [t[0] for t in operations], selected_math),
('ZCOMBINE', ('MIX', ), selected_z),
@@ -2362,158 +2583,191 @@ class NWMergeNodes(Operator, NWBase):
if selected_mix and selected_math and merge_type == 'AUTO':
selected_mix += selected_math
selected_math = []
-
- for nodes_list in [selected_mix, selected_shader, selected_math, selected_z, selected_alphaover]:
- if nodes_list:
- count_before = len(nodes)
- # sort list by loc_x - reversed
- nodes_list.sort(key=lambda k: k[1], reverse=True)
- # get maximum loc_x
- loc_x = nodes_list[0][1] + nodes_list[0][3] + 70
- nodes_list.sort(key=lambda k: k[2], reverse=True)
- if merge_position == 'CENTER':
- loc_y = ((nodes_list[len(nodes_list) - 1][2]) + (nodes_list[len(nodes_list) - 2][2])) / 2 # average yloc of last two nodes (lowest two)
- if nodes_list[len(nodes_list) - 1][-1] == True: # if last node is hidden, mix should be shifted up a bit
- if do_hide:
- loc_y += 40
- else:
- loc_y += 80
+ for nodes_list in [selected_mix, selected_shader, selected_geometry, selected_math, selected_vector, selected_z, selected_alphaover]:
+ if not nodes_list:
+ continue
+ count_before = len(nodes)
+ # sort list by loc_x - reversed
+ nodes_list.sort(key=lambda k: k[1], reverse=True)
+ # get maximum loc_x
+ loc_x = nodes_list[0][1] + nodes_list[0][3] + 70
+ nodes_list.sort(key=lambda k: k[2], reverse=True)
+
+ # Change the node type for math nodes in a geometry node tree.
+ if tree_type == 'GEOMETRY':
+ if nodes_list is selected_math or nodes_list is selected_vector:
+ node_type = 'ShaderNode'
+ if mode == 'MIX':
+ mode = 'ADD'
else:
- loc_y = nodes_list[len(nodes_list) - 1][2]
- offset_y = 100
- if not do_hide:
- offset_y = 200
- if nodes_list == selected_shader and not do_hide_shader:
- offset_y = 150.0
- the_range = len(nodes_list) - 1
- if len(nodes_list) == 1:
- the_range = 1
- for i in range(the_range):
- if nodes_list == selected_mix:
- add_type = node_type + 'MixRGB'
+ node_type = 'GeometryNode'
+ if merge_position == 'CENTER':
+ loc_y = ((nodes_list[len(nodes_list) - 1][2]) + (nodes_list[len(nodes_list) - 2][2])) / 2 # average yloc of last two nodes (lowest two)
+ if nodes_list[len(nodes_list) - 1][-1] == True: # if last node is hidden, mix should be shifted up a bit
+ if do_hide:
+ loc_y += 40
+ else:
+ loc_y += 80
+ else:
+ loc_y = nodes_list[len(nodes_list) - 1][2]
+ offset_y = 100
+ if not do_hide:
+ offset_y = 200
+ if nodes_list == selected_shader and not do_hide_shader:
+ offset_y = 150.0
+ the_range = len(nodes_list) - 1
+ if len(nodes_list) == 1:
+ the_range = 1
+ was_multi = False
+ for i in range(the_range):
+ if nodes_list == selected_mix:
+ add_type = node_type + 'MixRGB'
+ add = nodes.new(add_type)
+ add.blend_type = mode
+ if mode != 'MIX':
+ add.inputs[0].default_value = 1.0
+ add.show_preview = False
+ add.hide = do_hide
+ if do_hide:
+ loc_y = loc_y - 50
+ first = 1
+ second = 2
+ add.width_hidden = 100.0
+ elif nodes_list == selected_math:
+ add_type = node_type + 'Math'
+ add = nodes.new(add_type)
+ add.operation = mode
+ add.hide = do_hide
+ if do_hide:
+ loc_y = loc_y - 50
+ first = 0
+ second = 1
+ add.width_hidden = 100.0
+ elif nodes_list == selected_shader:
+ if mode == 'MIX':
+ add_type = node_type + 'MixShader'
add = nodes.new(add_type)
- add.blend_type = mode
- if mode != 'MIX':
- add.inputs[0].default_value = 1.0
- add.show_preview = False
- add.hide = do_hide
- if do_hide:
+ add.hide = do_hide_shader
+ if do_hide_shader:
loc_y = loc_y - 50
first = 1
second = 2
add.width_hidden = 100.0
- elif nodes_list == selected_math:
- add_type = node_type + 'Math'
+ elif mode == 'ADD':
+ add_type = node_type + 'AddShader'
add = nodes.new(add_type)
- add.operation = mode
- add.hide = do_hide
- if do_hide:
+ add.hide = do_hide_shader
+ if do_hide_shader:
loc_y = loc_y - 50
first = 0
second = 1
add.width_hidden = 100.0
- elif nodes_list == selected_shader:
- if mode == 'MIX':
- add_type = node_type + 'MixShader'
- add = nodes.new(add_type)
- add.hide = do_hide_shader
- if do_hide_shader:
- loc_y = loc_y - 50
- first = 1
- second = 2
- add.width_hidden = 100.0
- elif mode == 'ADD':
- add_type = node_type + 'AddShader'
- add = nodes.new(add_type)
- add.hide = do_hide_shader
- if do_hide_shader:
- loc_y = loc_y - 50
- first = 0
- second = 1
- add.width_hidden = 100.0
- elif nodes_list == selected_z:
- add = nodes.new('CompositorNodeZcombine')
- add.show_preview = False
- add.hide = do_hide
- if do_hide:
- loc_y = loc_y - 50
- first = 0
- second = 2
- add.width_hidden = 100.0
- elif nodes_list == selected_alphaover:
- add = nodes.new('CompositorNodeAlphaOver')
- add.show_preview = False
- add.hide = do_hide
- if do_hide:
- loc_y = loc_y - 50
- first = 1
- second = 2
- add.width_hidden = 100.0
- add.location = loc_x, loc_y
- loc_y += offset_y
- add.select = True
- count_adds = i + 1
- count_after = len(nodes)
- index = count_after - 1
- first_selected = nodes[nodes_list[0][0]]
- # "last" node has been added as first, so its index is count_before.
- last_add = nodes[count_before]
- # Special case:
- # Two nodes were selected and first selected has no output links, second selected has output links.
- # Then add links from last add to all links 'to_socket' of out links of second selected.
- if len(nodes_list) == 2:
- if not first_selected.outputs[0].links:
- second_selected = nodes[nodes_list[1][0]]
- for ss_link in second_selected.outputs[0].links:
- # Prevent cyclic dependencies when nodes to be marged are linked to one another.
- # Create list of invalid indexes.
- invalid_i = [n[0] for n in (selected_mix + selected_math + selected_shader + selected_z)]
- # Link only if "to_node" index not in invalid indexes list.
- if ss_link.to_node not in [nodes[i] for i in invalid_i]:
- links.new(last_add.outputs[0], ss_link.to_socket)
- # add links from last_add to all links 'to_socket' of out links of first selected.
- for fs_link in first_selected.outputs[0].links:
- # Prevent cyclic dependencies when nodes to be marged are linked to one another.
- # Create list of invalid indexes.
- invalid_i = [n[0] for n in (selected_mix + selected_math + selected_shader + selected_z)]
- # Link only if "to_node" index not in invalid indexes list.
- if fs_link.to_node not in [nodes[i] for i in invalid_i]:
- links.new(last_add.outputs[0], fs_link.to_socket)
- # add link from "first" selected and "first" add node
- node_to = nodes[count_after - 1]
- links.new(first_selected.outputs[0], node_to.inputs[first])
- if node_to.type == 'ZCOMBINE':
- for fs_out in first_selected.outputs:
- if fs_out != first_selected.outputs[0] and fs_out.name in ('Z', 'Depth'):
- links.new(fs_out, node_to.inputs[1])
- break
- # add links between added ADD nodes and between selected and ADD nodes
- for i in range(count_adds):
- if i < count_adds - 1:
- node_from = nodes[index]
- node_to = nodes[index - 1]
- node_to_input_i = first
- node_to_z_i = 1 # if z combine - link z to first z input
- links.new(node_from.outputs[0], node_to.inputs[node_to_input_i])
- if node_to.type == 'ZCOMBINE':
- for from_out in node_from.outputs:
- if from_out != node_from.outputs[0] and from_out.name in ('Z', 'Depth'):
- links.new(from_out, node_to.inputs[node_to_z_i])
- if len(nodes_list) > 1:
- node_from = nodes[nodes_list[i + 1][0]]
- node_to = nodes[index]
- node_to_input_i = second
- node_to_z_i = 3 # if z combine - link z to second z input
- links.new(node_from.outputs[0], node_to.inputs[node_to_input_i])
- if node_to.type == 'ZCOMBINE':
- for from_out in node_from.outputs:
- if from_out != node_from.outputs[0] and from_out.name in ('Z', 'Depth'):
- links.new(from_out, node_to.inputs[node_to_z_i])
- index -= 1
- # set "last" of added nodes as active
- nodes.active = last_add
- for i, x, y, dx, h in nodes_list:
- nodes[i].select = False
+ elif nodes_list == selected_geometry:
+ if mode in ('JOIN', 'MIX'):
+ add_type = node_type + 'JoinGeometry'
+ add = self.merge_with_multi_input(nodes_list, merge_position, do_hide, loc_x, links, nodes, add_type,[0])
+ else:
+ add_type = node_type + 'Boolean'
+ indices = [0,1] if mode == 'DIFFERENCE' else [1]
+ add = self.merge_with_multi_input(nodes_list, merge_position, do_hide, loc_x, links, nodes, add_type,indices)
+ add.operation = mode
+ was_multi = True
+ break
+ elif nodes_list == selected_vector:
+ add_type = node_type + 'VectorMath'
+ add = nodes.new(add_type)
+ add.operation = mode
+ add.hide = do_hide
+ if do_hide:
+ loc_y = loc_y - 50
+ first = 0
+ second = 1
+ add.width_hidden = 100.0
+ elif nodes_list == selected_z:
+ add = nodes.new('CompositorNodeZcombine')
+ add.show_preview = False
+ add.hide = do_hide
+ if do_hide:
+ loc_y = loc_y - 50
+ first = 0
+ second = 2
+ add.width_hidden = 100.0
+ elif nodes_list == selected_alphaover:
+ add = nodes.new('CompositorNodeAlphaOver')
+ add.show_preview = False
+ add.hide = do_hide
+ if do_hide:
+ loc_y = loc_y - 50
+ first = 1
+ second = 2
+ add.width_hidden = 100.0
+ add.location = loc_x, loc_y
+ loc_y += offset_y
+ add.select = True
+
+ # This has already been handled separately
+ if was_multi:
+ continue
+ count_adds = i + 1
+ count_after = len(nodes)
+ index = count_after - 1
+ first_selected = nodes[nodes_list[0][0]]
+ # "last" node has been added as first, so its index is count_before.
+ last_add = nodes[count_before]
+ # Create list of invalid indexes.
+ invalid_nodes = [nodes[n[0]] for n in (selected_mix + selected_math + selected_shader + selected_z + selected_geometry)]
+
+ # Special case:
+ # Two nodes were selected and first selected has no output links, second selected has output links.
+ # Then add links from last add to all links 'to_socket' of out links of second selected.
+ if len(nodes_list) == 2:
+ if not first_selected.outputs[0].links:
+ second_selected = nodes[nodes_list[1][0]]
+ for ss_link in second_selected.outputs[0].links:
+ # Prevent cyclic dependencies when nodes to be merged are linked to one another.
+ # Link only if "to_node" index not in invalid indexes list.
+ if not self.link_creates_cycle(ss_link, invalid_nodes):
+ links.new(last_add.outputs[0], ss_link.to_socket)
+ # add links from last_add to all links 'to_socket' of out links of first selected.
+ for fs_link in first_selected.outputs[0].links:
+ # Link only if "to_node" index not in invalid indexes list.
+ if not self.link_creates_cycle(fs_link, invalid_nodes):
+ links.new(last_add.outputs[0], fs_link.to_socket)
+ # add link from "first" selected and "first" add node
+ node_to = nodes[count_after - 1]
+ links.new(first_selected.outputs[0], node_to.inputs[first])
+ if node_to.type == 'ZCOMBINE':
+ for fs_out in first_selected.outputs:
+ if fs_out != first_selected.outputs[0] and fs_out.name in ('Z', 'Depth'):
+ links.new(fs_out, node_to.inputs[1])
+ break
+ # add links between added ADD nodes and between selected and ADD nodes
+ for i in range(count_adds):
+ if i < count_adds - 1:
+ node_from = nodes[index]
+ node_to = nodes[index - 1]
+ node_to_input_i = first
+ node_to_z_i = 1 # if z combine - link z to first z input
+ links.new(node_from.outputs[0], node_to.inputs[node_to_input_i])
+ if node_to.type == 'ZCOMBINE':
+ for from_out in node_from.outputs:
+ if from_out != node_from.outputs[0] and from_out.name in ('Z', 'Depth'):
+ links.new(from_out, node_to.inputs[node_to_z_i])
+ if len(nodes_list) > 1:
+ node_from = nodes[nodes_list[i + 1][0]]
+ node_to = nodes[index]
+ node_to_input_i = second
+ node_to_z_i = 3 # if z combine - link z to second z input
+ links.new(node_from.outputs[0], node_to.inputs[node_to_input_i])
+ if node_to.type == 'ZCOMBINE':
+ for from_out in node_from.outputs:
+ if from_out != node_from.outputs[0] and from_out.name in ('Z', 'Depth'):
+ links.new(from_out, node_to.inputs[node_to_z_i])
+ index -= 1
+ # set "last" of added nodes as active
+ nodes.active = last_add
+ for i, x, y, dx, h in nodes_list:
+ nodes[i].select = False
return {'FINISHED'}
@@ -2534,12 +2788,10 @@ class NWBatchChangeNodes(Operator, NWBase):
)
def execute(self, context):
-
- nodes, links = get_nodes_links(context)
blend_type = self.blend_type
operation = self.operation
for node in context.selected_nodes:
- if node.type == 'MIX_RGB':
+ if node.type == 'MIX_RGB' or node.bl_idname == 'GeometryNodeAttributeMix':
if not blend_type in [nav[0] for nav in navs]:
node.blend_type = blend_type
else:
@@ -2558,7 +2810,7 @@ class NWBatchChangeNodes(Operator, NWBase):
else:
node.blend_type = blend_types[index - 1][0]
- if node.type == 'MATH':
+ if node.type == 'MATH' or node.bl_idname == 'GeometryNodeAttributeMath':
if not operation in [nav[0] for nav in navs]:
node.operation = operation
else:
@@ -3478,7 +3730,7 @@ class NWDetachOutputs(Operator, NWBase):
return {'FINISHED'}
-class NWLinkToOutputNode(Operator, NWBase):
+class NWLinkToOutputNode(Operator):
"""Link to Composite node or Material Output node"""
bl_idname = "node.nw_link_out"
bl_label = "Connect to Output"
@@ -3487,7 +3739,7 @@ class NWLinkToOutputNode(Operator, NWBase):
@classmethod
def poll(cls, context):
valid = False
- if nw_check(context):
+ if nw_check(context) and context.space_data.tree_type != 'GeometryNodeTree':
if context.active_node is not None:
for out in context.active_node.outputs:
if is_visible_socket(out):
@@ -3993,7 +4245,8 @@ def drawlayout(context, layout, mode='non-panel'):
col = layout.column(align=True)
col.menu(NWLinkActiveToSelectedMenu.bl_idname, text="Link Active To Selected", icon='LINKED')
- col.operator(NWLinkToOutputNode.bl_idname, icon='DRIVER')
+ if tree_type != 'GeometryNodeTree':
+ col.operator(NWLinkToOutputNode.bl_idname, icon='DRIVER')
col.separator()
col = layout.column(align=True)
@@ -4012,7 +4265,8 @@ def drawlayout(context, layout, mode='non-panel'):
col = layout.column(align=True)
if tree_type == 'CompositorNodeTree':
col.operator(NWResetBG.bl_idname, icon='ZOOM_PREVIOUS')
- col.operator(NWReloadImages.bl_idname, icon='FILE_REFRESH')
+ if tree_type != 'GeometryNodeTree':
+ col.operator(NWReloadImages.bl_idname, icon='FILE_REFRESH')
col.separator()
col = layout.column(align=True)
@@ -4067,15 +4321,29 @@ class NWMergeNodesMenu(Menu, NWBase):
layout = self.layout
if type == 'ShaderNodeTree':
layout.menu(NWMergeShadersMenu.bl_idname, text="Use Shaders")
- layout.menu(NWMergeMixMenu.bl_idname, text="Use Mix Nodes")
- layout.menu(NWMergeMathMenu.bl_idname, text="Use Math Nodes")
- props = layout.operator(NWMergeNodes.bl_idname, text="Use Z-Combine Nodes")
- props.mode = 'MIX'
- props.merge_type = 'ZCOMBINE'
- props = layout.operator(NWMergeNodes.bl_idname, text="Use Alpha Over Nodes")
- props.mode = 'MIX'
- props.merge_type = 'ALPHAOVER'
-
+ if type == 'GeometryNodeTree':
+ layout.menu(NWMergeGeometryMenu.bl_idname, text="Use Geometry Nodes")
+ layout.menu(NWMergeMathMenu.bl_idname, text="Use Math Nodes")
+ else:
+ layout.menu(NWMergeMixMenu.bl_idname, text="Use Mix Nodes")
+ layout.menu(NWMergeMathMenu.bl_idname, text="Use Math Nodes")
+ props = layout.operator(NWMergeNodes.bl_idname, text="Use Z-Combine Nodes")
+ props.mode = 'MIX'
+ props.merge_type = 'ZCOMBINE'
+ props = layout.operator(NWMergeNodes.bl_idname, text="Use Alpha Over Nodes")
+ props.mode = 'MIX'
+ props.merge_type = 'ALPHAOVER'
+
+class NWMergeGeometryMenu(Menu, NWBase):
+ bl_idname = "NODE_MT_nw_merge_geometry_menu"
+ bl_label = "Merge Selected Nodes using Geometry Nodes"
+ def draw(self, context):
+ layout = self.layout
+ # The boolean node + Join Geometry node
+ for type, name, description in geo_combine_operations:
+ props = layout.operator(NWMergeNodes.bl_idname, text=name)
+ props.mode = type
+ props.merge_type = 'GEOMETRY'
class NWMergeShadersMenu(Menu, NWBase):
bl_idname = "NODE_MT_nw_merge_shaders_menu"
@@ -4110,18 +4378,12 @@ class NWConnectionListOutputs(Menu, NWBase):
nodes, links = get_nodes_links(context)
n1 = nodes[context.scene.NWLazySource]
-
- if n1.type == "R_LAYERS":
- index=0
- for o in n1.outputs:
- if o.enabled: # Check which passes the render layer has enabled
- layout.operator(NWCallInputsMenu.bl_idname, text=o.name, icon="RADIOBUT_OFF").from_socket=index
- index+=1
- else:
- index=0
- for o in n1.outputs:
+ index=0
+ for o in n1.outputs:
+ # Only show sockets that are exposed.
+ if o.enabled:
layout.operator(NWCallInputsMenu.bl_idname, text=o.name, icon="RADIOBUT_OFF").from_socket=index
- index+=1
+ index+=1
class NWConnectionListInputs(Menu, NWBase):
@@ -4136,10 +4398,15 @@ class NWConnectionListInputs(Menu, NWBase):
index = 0
for i in n2.inputs:
- op = layout.operator(NWMakeLink.bl_idname, text=i.name, icon="FORWARD")
- op.from_socket = context.scene.NWSourceSocket
- op.to_socket = index
- index+=1
+ # Only show sockets that are exposed.
+ # This prevents, for example, the scale value socket
+ # of the vector math node being added to the list when
+ # the mode is not 'SCALE'.
+ if i.enabled:
+ op = layout.operator(NWMakeLink.bl_idname, text=i.name, icon="FORWARD")
+ op.from_socket = context.scene.NWSourceSocket
+ op.to_socket = index
+ index+=1
class NWMergeMathMenu(Menu, NWBase):
@@ -4351,6 +4618,17 @@ class NWSwitchNodeTypeMenu(Menu, NWBase):
layout.menu(NWSwitchTexConverterSubmenu.bl_idname)
layout.menu(NWSwitchTexDistortSubmenu.bl_idname)
layout.menu(NWSwitchTexLayoutSubmenu.bl_idname)
+ if tree.type == 'GEOMETRY':
+ categories = [c for c in node_categories_iter(context)
+ if c.name not in ['Group', 'Script']]
+ for cat in categories:
+ idname = f"NODE_MT_nw_switch_{cat.identifier}_submenu"
+ if hasattr(bpy.types, idname):
+ layout.menu(idname)
+ else:
+ layout.label(text="Unable to load altered node lists.")
+ layout.label(text="Please re-enable Node Wrangler.")
+ break
class NWSwitchShadersInputSubmenu(Menu, NWBase):
@@ -4697,6 +4975,17 @@ class NWSwitchTexLayoutSubmenu(Menu, NWBase):
props = layout.operator(NWSwitchNodeType.bl_idname, text=rna_name)
props.to_type = ident
+def draw_switch_category_submenu(self, context):
+ layout = self.layout
+ if self.category.name == 'Layout':
+ for node in self.category.items(context):
+ if node.nodetype != 'NodeFrame':
+ props = layout.operator(NWSwitchNodeType.bl_idname, text=node.label)
+ props.to_type = node.nodetype
+ else:
+ for node in self.category.items(context):
+ props = layout.operator(NWSwitchNodeType.bl_idname, text=node.label)
+ props.geo_to_type = node.nodetype
#
# APPENDAGES TO EXISTING UI
@@ -4754,7 +5043,7 @@ def reset_nodes_button(self, context):
#
# REGISTER/UNREGISTER CLASSES AND KEYMAP ITEMS
#
-
+switch_category_menus = []
addon_keymaps = []
# kmi_defs entry: (identifier, key, action, CTRL, SHIFT, ALT, props, nice name)
# props entry: (property name, property value)
@@ -4916,8 +5205,8 @@ kmi_defs = (
(NWFrameSelected.bl_idname, 'P', 'PRESS', False, True, False, None, "Frame selected nodes"),
# Swap Outputs
(NWSwapLinks.bl_idname, 'S', 'PRESS', False, False, True, None, "Swap Outputs"),
- # Emission Viewer
- (NWEmissionViewer.bl_idname, 'LEFTMOUSE', 'PRESS', True, True, False, None, "Connect to Cycles Viewer node"),
+ # Preview Node
+ (NWPreviewNode.bl_idname, 'LEFTMOUSE', 'PRESS', True, True, False, None, "Preview node output"),
# Reload Images
(NWReloadImages.bl_idname, 'R', 'PRESS', False, False, True, None, "Reload images"),
# Lazy Mix
@@ -4951,7 +5240,7 @@ classes = (
NWSwapLinks,
NWResetBG,
NWAddAttrNode,
- NWEmissionViewer,
+ NWPreviewNode,
NWFrameSelected,
NWReloadImages,
NWSwitchNodeType,
@@ -4981,6 +5270,7 @@ classes = (
NodeWranglerMenu,
NWMergeNodesMenu,
NWMergeShadersMenu,
+ NWMergeGeometryMenu,
NWMergeMixMenu,
NWConnectionListOutputs,
NWConnectionListInputs,
@@ -5081,6 +5371,23 @@ def register():
bpy.types.NODE_PT_active_node_generic.prepend(reset_nodes_button)
bpy.types.NODE_MT_node.prepend(reset_nodes_button)
+ # switch submenus
+ switch_category_menus.clear()
+ for cat in node_categories_iter(None):
+ if cat.name not in ['Group', 'Script'] and cat.identifier.startswith('GEO'):
+ idname = f"NODE_MT_nw_switch_{cat.identifier}_submenu"
+ switch_category_type = type(idname, (bpy.types.Menu,), {
+ "bl_space_type": 'NODE_EDITOR',
+ "bl_label": cat.name,
+ "category": cat,
+ "poll": cat.poll,
+ "draw": draw_switch_category_submenu,
+ })
+
+ switch_category_menus.append(switch_category_type)
+
+ bpy.utils.register_class(switch_category_type)
+
def unregister():
from bpy.utils import unregister_class
@@ -5092,6 +5399,10 @@ def unregister():
del bpy.types.Scene.NWSourceSocket
del bpy.types.NodeSocketInterface.NWViewerSocket
+ for cat_types in switch_category_menus:
+ bpy.utils.unregister_class(cat_types)
+ switch_category_menus.clear()
+
# keymaps
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
diff --git a/presets/pov/light/02_(5400K)_High_Noon_Sun.py b/presets/pov/light/02_(5400K)_High_Noon_Sun.py
index 47499b52..7b5b9e2e 100644..100755
--- a/presets/pov/light/02_(5400K)_High_Noon_Sun.py
+++ b/presets/pov/light/02_(5400K)_High_Noon_Sun.py
@@ -9,8 +9,8 @@ lampdata = bpy.context.object.data
lampdata.shape = 'SQUARE'
lampdata.size = 30000000#0.02
#lampdata.size_y = 0.02
-lampdata.shadow_ray_samples_x = 2
-#lampdata.shadow_ray_samples_y = 3
+lampdata.pov.shadow_ray_samples_x = 2
+#lampdata.pov.shadow_ray_samples_y = 3
lampdata.color = (1.0, 1.0, 1.0)
lampdata.energy = 1.094316#91193 #lux
lampdata.distance =695699968
diff --git a/presets/pov/light/03_(6000K)_Daylight_Window.py b/presets/pov/light/03_(6000K)_Daylight_Window.py
index a9781f57..eae7cd16 100644..100755
--- a/presets/pov/light/03_(6000K)_Daylight_Window.py
+++ b/presets/pov/light/03_(6000K)_Daylight_Window.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
lampdata.size = 1.2
lampdata.size_y = 2.10
-lampdata.shadow_ray_samples_x = 2
-lampdata.shadow_ray_samples_y = 3
+lampdata.pov.shadow_ray_samples_x = 2
+lampdata.pov.shadow_ray_samples_y = 3
lampdata.color = (1.0, 1.0, 1.0)
lampdata.energy = 1.094316#91193 #lux
lampdata.distance = 1.0
diff --git a/presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py b/presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py
index 78fa29cb..6d09b96f 100644..100755
--- a/presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py
+++ b/presets/pov/light/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
lampdata.size = 0.038
lampdata.size_y = 2.40284
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
lampdata.color = (1.0, 0.95686274766922, 0.9490200281143188)
lampdata.energy = 4.45304#4775lm/21.446(=lux)*0.004(distance) *2 for distance is the point of half strength 6200lm?
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py b/presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py
index dc78bc5c..5a5a7eb9 100644..100755
--- a/presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py
+++ b/presets/pov/light/10_(4300K)_40W_Vintage_Fluorescent_T12.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
lampdata.size = 0.038
lampdata.size_y = 1.2192
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
lampdata.color = (0.901, 1.0, 0.979)
lampdata.energy = 2.14492#2300lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py b/presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py
index a70cda3f..5f7ce0a6 100644..100755
--- a/presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py
+++ b/presets/pov/light/11_(5000K)_18W_Standard_Fluorescent_T8.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
lampdata.size = 0.026
lampdata.size_y = 0.59
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
lampdata.color = (0.95686274766922, 1.0, 0.9803921580314636)
lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py b/presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py
index c2a0d65d..0bbf1965 100644..100755
--- a/presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py
+++ b/presets/pov/light/12_(4200K)_18W_Cool_White_Fluorescent_T8.py
@@ -7,8 +7,8 @@ lampdata = bpy.context.object.data
lampdata.size = 0.026
lampdata.size_y = 0.59
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
lampdata.color = (0.8313725590705872, 0.9215686321258545, 1.0)
lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py b/presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py
index e1cee557..187b26d3 100644..100755
--- a/presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py
+++ b/presets/pov/light/13_(3000K)_18W_Warm_Fluorescent_T8.py
@@ -7,8 +7,8 @@ lampdata = bpy.context.object.data
lampdata.size = 0.026
lampdata.size_y = 0.59
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
lampdata.color = (1.0, 0.95686274766922, 0.8980392217636108)
lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py b/presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py
index 55f84ab8..c0b992ca 100644..100755
--- a/presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py
+++ b/presets/pov/light/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py
@@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
lampdata.size = 0.016
lampdata.size_y = 1.149
-lampdata.shadow_ray_samples_x = 1
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 1
+lampdata.pov.shadow_ray_samples_y = 2
lampdata.color = (1.0, 0.83, 0.986274528503418)
lampdata.energy = 4.66287 #0.93257#4.66287#5000lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
lampdata.distance = 0.1 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/light/21_(2700K)_7W_OLED_Panel.py b/presets/pov/light/21_(2700K)_7W_OLED_Panel.py
index 8f2ebb8f..8a6ba8d9 100644..100755
--- a/presets/pov/light/21_(2700K)_7W_OLED_Panel.py
+++ b/presets/pov/light/21_(2700K)_7W_OLED_Panel.py
@@ -7,8 +7,8 @@ lampdata = bpy.context.object.data
lampdata.size = 0.033
lampdata.size_y = 0.133
-lampdata.shadow_ray_samples_x = 2
-lampdata.shadow_ray_samples_y = 2
+lampdata.pov.shadow_ray_samples_x = 2
+lampdata.pov.shadow_ray_samples_y = 2
lampdata.color = (1.0, 0.8292156958580017, 0.6966666865348816)
lampdata.energy = 0.83932#900lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
lampdata.distance = 1.18 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/render_povray/__init__.py b/render_povray/__init__.py
index da7296a9..f0734c5f 100644..100755
--- a/render_povray/__init__.py
+++ b/render_povray/__init__.py
@@ -24,29 +24,83 @@ These engines can be POV-Ray or Uberpov but others too, since POV is a
Scene Description Language. The script has been split in as few files
as possible :
-___init__.py :
+__init__.py :
Initialize properties
-update_files.py
- Update new variables to values from older API. This file needs an update
-
-ui.py :
+base_ui.py :
Provide property buttons for the user to set up the variables
-primitives.py :
+scenography_properties.py
+ Initialize properties for translating Blender cam/light/environment parameters to pov
+
+scenography_gui.py
+ Display cam/light/environment properties from situation_properties.py for user to change them
+
+scenography.py
+ Translate cam/light/environment properties to corresponding pov features
+
+object_properties.py :
+ nitialize properties for translating Blender objects parameters to pov
+
+object_primitives.py :
Display some POV native primitives in 3D view for input and output
+object_mesh_topology.py :
+ Translate to POV the meshes geometries
+
+object_curve_topology.py :
+ Translate to POV the curve based geometries
+
+object_particles.py :
+ Translate to POV the particle based geometries
+
+object_gui.py :
+ Display properties from object_properties.py for user to change them
+
+shading_properties.py
+ Initialize properties for translating Blender materials parameters to pov
+
+shading_nodes.py
+ Translate node trees to the pov file
+
+shading_gui.py
+ Display properties from shading_properties.py for user to change them
+
shading.py
Translate shading properties to declared textures at the top of a pov file
-nodes.py
- Translate node trees to the pov file
+texturing_properties.py
+ Initialize properties for translating Blender materials /world... texture influences to pov
-df3.py
- Render smoke to *.df3 files
+texturing_gui.py
+ Display properties from texturing_properties.py for user to change them
+
+texturing.py
+ Translate blender texture influences into POV
+
+render_properties.py :
+ Initialize properties for render parameters (Blender and POV native)
+
+render_gui.py :
+ Display properties from render_properties.py for user to change them
render.py :
- Translate geometry and UI properties (Blender and POV native) to the POV file
+ Translate render properties (Blender and POV native) to POV, ini file and bash
+
+scripting_properties.py :
+ Initialize properties for scene description language parameters (POV native)
+
+scripting_gui.py :
+ Display properties from scripting_properties.py for user to add his custom POV code
+
+scripting.py :
+ Insert POV native scene description elements to exported POV file
+
+df3_library.py
+ Render smoke to *.df3 files
+
+update_files.py
+ Update new variables to values from older API. This file needs an update
Along these essential files also coexist a few additional libraries to help make
@@ -99,5417 +153,187 @@ Blender stand up to other POV IDEs such as povwin or QTPOV
bl_info = {
"name": "Persistence of Vision",
"author": "Campbell Barton, "
- "Maurice Raybaud, "
- "Leonid Desyatkov, "
- "Bastien Montagne, "
- "Constantin Rahn, "
- "Silvio Falcinelli",
- "version": (0, 1, 1),
+ "Maurice Raybaud, "
+ "Leonid Desyatkov, "
+ "Bastien Montagne, "
+ "Constantin Rahn, "
+ "Silvio Falcinelli,"
+ "Paco García",
+ "version": (0, 1, 2),
"blender": (2, 81, 0),
"location": "Render Properties > Render Engine > Persistence of Vision",
"description": "Persistence of Vision integration for blender",
"doc_url": "{BLENDER_MANUAL_URL}/addons/render/povray.html",
"category": "Render",
- "warning": "Under active development, seeking co-maintainer(s)",
+ "warning": "Co-maintainers welcome",
}
+# Other occasional contributors, more or less in chronological order:
+# Luca Bonavita ; Shane Ambler ; Brendon Murphy ; Doug Hammond ;
+# Thomas Dinges ; Jonathan Smith ; Sebastian Nell ; Philipp Oeser ;
+# Sybren A. Stüvel ; Dalai Felinto ; Sergey Sharybin ; Brecht Van Lommel ;
+# Stephen Leger ; Rune Morling ; Aaron Carlisle ; Ankit Meel ;
+
if "bpy" in locals():
import importlib
- importlib.reload(ui)
- importlib.reload(nodes)
+ importlib.reload(base_ui)
+ importlib.reload(shading_nodes)
+ importlib.reload(scenography_properties)
+ importlib.reload(scenography)
+ importlib.reload(render_properties)
+ importlib.reload(render_gui)
importlib.reload(render)
+ importlib.reload(shading_properties)
+ importlib.reload(shading_gui)
importlib.reload(shading)
- importlib.reload(primitives)
+ importlib.reload(texturing_properties)
+ importlib.reload(texturing_gui)
+ importlib.reload(texturing)
+ importlib.reload(object_properties)
+ importlib.reload(object_gui)
+ importlib.reload(object_mesh_topology)
+ importlib.reload(object_curve_topology)
+ importlib.reload(object_primitives)
+ importlib.reload(scripting_gui)
importlib.reload(update_files)
else:
import bpy
from bpy.utils import register_class, unregister_class
- # import addon_utils # To use some other addons
- import nodeitems_utils # for Nodes
- from nodeitems_utils import NodeCategory, NodeItem # for Nodes
- from bl_operators.presets import AddPresetBase
- from bpy.types import (
- AddonPreferences,
- PropertyGroup,
- NodeSocket,
- )
-
- from bpy.props import (
- FloatVectorProperty,
- StringProperty,
- BoolProperty,
- IntProperty,
- FloatProperty,
- EnumProperty,
- PointerProperty,
- CollectionProperty,
- )
- from . import ui, render, update_files
-
-
-def string_strip_hyphen(name):
-
- """Remove hyphen characters from a string to avoid POV errors"""
-
- return name.replace("-", "")
-
-def pov_context_tex_datablock(context):
- """Texture context type recreated as deprecated in blender 2.8"""
-
- idblock = context.brush
- if idblock and context.scene.texture_context == 'OTHER':
- return idblock
-
- # idblock = bpy.context.active_object.active_material
- idblock = context.view_layer.objects.active.active_material
- if idblock and context.scene.texture_context == 'MATERIAL':
- return idblock
-
- idblock = context.world
- if idblock and context.scene.texture_context == 'WORLD':
- return idblock
-
- idblock = context.light
- if idblock and context.scene.texture_context == 'LIGHT':
- return idblock
-
- if context.particle_system and context.scene.texture_context == 'PARTICLES':
- idblock = context.particle_system.settings
-
- return idblock
-
- idblock = context.line_style
- if idblock and context.scene.texture_context == 'LINESTYLE':
- return idblock
-
-def brush_texture_update(self, context):
-
- """Brush texture rolldown must show active slot texture props"""
- idblock = pov_context_tex_datablock(context)
- if idblock is not None:
- #mat = context.view_layer.objects.active.active_material
- idblock = pov_context_tex_datablock(context)
- slot = idblock.pov_texture_slots[idblock.pov.active_texture_index]
- tex = slot.texture
-
- if tex:
- # Switch paint brush to active texture so slot and settings remain contextual
- bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
- bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
-
-def active_texture_name_from_uilist(self, context):
-
- idblock = pov_context_tex_datablock(context)
- #mat = context.view_layer.objects.active.active_material
- if idblock is not None:
- index = idblock.pov.active_texture_index
- name = idblock.pov_texture_slots[index].name
- newname = idblock.pov_texture_slots[index].texture
- tex = bpy.data.textures[name]
- tex.name = newname
- idblock.pov_texture_slots[index].name = newname
-
-
-def active_texture_name_from_search(self, context):
- """Texture rolldown to change the data linked by an existing texture"""
- idblock = pov_context_tex_datablock(context)
- #mat = context.view_layer.objects.active.active_material
- if idblock is not None:
- index = idblock.pov.active_texture_index
- slot = idblock.pov_texture_slots[index]
- name = slot.texture_search
-
- try:
- tex = bpy.data.textures[name]
- slot.name = name
- slot.texture = name
- # Switch paint brush to this texture so settings remain contextual
- #bpy.context.tool_settings.image_paint.brush.texture = tex
- #bpy.context.tool_settings.image_paint.brush.mask_texture = tex
- except:
- pass
-
-
-
-###############################################################################
-# Scene POV properties.
-###############################################################################
-class RenderPovSettingsScene(PropertyGroup):
-
- """Declare scene level properties controllable in UI and translated to POV"""
-
- # Linux SDL-window enable
- sdl_window_enable: BoolProperty(
- name="Enable SDL window",
- description="Enable the SDL window in Linux OS",
- default=True,
- )
- # File Options
- text_block: StringProperty(
- name="Text Scene Name",
- description="Name of POV scene to use. "
- "Set when clicking Run to render current text only",
- maxlen=1024,
- )
- tempfiles_enable: BoolProperty(
- name="Enable Tempfiles",
- description="Enable the OS-Tempfiles. Otherwise set the path where"
- " to save the files",
- default=True,
- )
- pov_editor: BoolProperty(
- name="POV editor",
- description="Don't Close POV editor after rendering (Overridden"
- " by /EXIT command)",
- default=False,
- )
- deletefiles_enable: BoolProperty(
- name="Delete files",
- description="Delete files after rendering. "
- "Doesn't work with the image",
- default=True,
- )
- scene_name: StringProperty(
- name="Scene Name",
- description="Name of POV scene to create. Empty name will use "
- "the name of the blend file",
- maxlen=1024,
- )
- scene_path: StringProperty(
- name="Export scene path",
- # Bug in POV-Ray RC3
- # description="Path to directory where the exported scene "
- # "(POV and INI) is created",
- description="Path to directory where the files are created",
- maxlen=1024,
- subtype="DIR_PATH",
- )
- renderimage_path: StringProperty(
- name="Rendered image path",
- description="Full path to directory where the rendered image is "
- "saved",
- maxlen=1024,
- subtype="DIR_PATH",
- )
- list_lf_enable: BoolProperty(
- name="LF in lists",
- description="Enable line breaks in lists (vectors and indices). "
- "Disabled: lists are exported in one line",
- default=True,
- )
-
- # Not a real pov option, just to know if we should write
- radio_enable: BoolProperty(
- name="Enable Radiosity",
- description="Enable POV radiosity calculation",
- default=True,
- )
-
- radio_display_advanced: BoolProperty(
- name="Advanced Options",
- description="Show advanced options",
- default=False,
- )
-
- media_enable: BoolProperty(
- name="Enable Media",
- description="Enable POV atmospheric media",
- default=False,
- )
-
- media_samples: IntProperty(
- name="Samples",
- description="Number of samples taken from camera to first object "
- "encountered along ray path for media calculation",
- min=1,
- max=100,
- default=35,
- )
-
- media_scattering_type: EnumProperty(
- name="Scattering Type",
- description="Scattering model",
- items=(
- (
- '1',
- "1 Isotropic",
- "The simplest form of scattering because"
- " it is independent of direction."
- ),
- (
- '2',
- "2 Mie haze ",
- "For relatively small particles such as "
- "minuscule water droplets of fog, cloud "
- "particles, and particles responsible "
- "for the polluted sky. In this model the"
- " scattering is extremely directional in"
- " the forward direction i.e. the amount "
- "of scattered light is largest when the "
- "incident light is anti-parallel to the "
- "viewing direction (the light goes "
- "directly to the viewer). It is smallest"
- " when the incident light is parallel to"
- " the viewing direction. "
- ),
- (
- '3',
- "3 Mie murky",
- "Like haze but much more directional"
- ),
- (
- '4',
- "4 Rayleigh",
- "For extremely small particles such as "
- "molecules of the air. The amount of "
- "scattered light depends on the incident"
- " light angle. It is largest when the "
- "incident light is parallel or "
- "anti-parallel to the viewing direction "
- "and smallest when the incident light is "
- "perpendicular to viewing direction."
- ),
- (
- '5',
- "5 Henyey-Greenstein",
- "The default eccentricity value "
- "of zero defines isotropic "
- "scattering while positive "
- "values lead to scattering in "
- "the direction of the light and "
- "negative values lead to "
- "scattering in the opposite "
- "direction of the light. Larger "
- "values of e (or smaller values "
- "in the negative case) increase "
- "the directional property of the"
- " scattering."
- )
- ),
- default='1',
- )
-
- media_diffusion_scale: FloatProperty(
- name="Scale",
- description="Scale factor of Media Diffusion Color",
- precision=6, step=0.00000001, min=0.000000001, max=1.0,
- default=(1.0),
- )
-
- media_diffusion_color: FloatVectorProperty(
- name="Media Diffusion Color",
- description="The atmospheric media color",
- precision=4, step=0.01, min=0, soft_max=1,
- default=(0.001, 0.001, 0.001),
- options={'ANIMATABLE'},
- subtype='COLOR',
- )
-
- media_absorption_scale: FloatProperty(
- name="Scale",
- description="Scale factor of Media Absorption Color. "
- "use 1/depth of media volume in meters",
- precision=6,
- step=0.000001,
- min=0.000000001,
- max=1.0,
- default=(0.00002),
- )
-
- media_absorption_color: FloatVectorProperty(
- name="Media Absorption Color",
- description="The atmospheric media absorption color",
- precision=4, step=0.01, min=0, soft_max=1,
- default=(0.0, 0.0, 0.0),
- options={'ANIMATABLE'},
- subtype='COLOR',
- )
-
- media_eccentricity: FloatProperty(
- name="Media Eccenticity Factor",
- description="Positive values lead"
- " to scattering in the direction of the light and negative "
- "values lead to scattering in the opposite direction of the "
- "light. Larger values of e (or smaller values in the negative"
- " case) increase the directional property of the scattering",
- precision=2,
- step=0.01,
- min=-1.0,
- max=1.0,
- default=(0.0),
- options={'ANIMATABLE'},
- )
-
- baking_enable: BoolProperty(
- name="Enable Baking",
- description="Enable POV texture baking",
- default=False
- )
-
- indentation_character: EnumProperty(
- name="Indentation",
- description="Select the indentation type",
- items=(
- ('NONE', "None", "No indentation"),
- ('TAB', "Tabs", "Indentation with tabs"),
- ('SPACE', "Spaces", "Indentation with spaces")
- ),
- default='SPACE'
- )
-
- indentation_spaces: IntProperty(
- name="Quantity of spaces",
- description="The number of spaces for indentation",
- min=1,
- max=10,
- default=4,
- )
-
- comments_enable: BoolProperty(
- name="Enable Comments",
- description="Add comments to pov file",
- default=True,
- )
-
- # Real pov options
- command_line_switches: StringProperty(
- name="Command Line Switches",
- description="Command line switches consist of a + (plus) or - "
- "(minus) sign, followed by one or more alphabetic "
- "characters and possibly a numeric value",
- maxlen=500,
- )
-
- antialias_enable: BoolProperty(
- name="Anti-Alias", description="Enable Anti-Aliasing",
- default=True,
- )
-
- antialias_method: EnumProperty(
- name="Method",
- description="AA-sampling method. Type 1 is an adaptive, "
- "non-recursive, super-sampling method. Type 2 is an "
- "adaptive and recursive super-sampling method. Type 3 "
- "is a stochastic halton based super-sampling method",
- items=(
- ("0", "non-recursive AA", "Type 1 Sampling in POV"),
- ("1", "recursive AA", "Type 2 Sampling in POV"),
- ("2", "stochastic AA", "Type 3 Sampling in POV")
- ),
- default="1",
- )
-
- antialias_confidence: FloatProperty(
- name="Antialias Confidence",
- description="how surely the computed color "
- "of a given pixel is indeed"
- "within the threshold error margin",
- min=0.0001,
- max=1.0000,
- default=0.9900,
- precision=4
- )
-
- antialias_depth: IntProperty(
- name="Antialias Depth",
- description="Depth of pixel for sampling",
- min=1,
- max=9,
- default=3
- )
-
- antialias_threshold: FloatProperty(
- name="Antialias Threshold",
- description="Tolerance for sub-pixels",
- min=0.0,
- max=1.0,
- soft_min=0.05,
- soft_max=0.5,
- default=0.03,
- )
-
- jitter_enable: BoolProperty(
- name="Jitter",
- description="Enable Jittering. Adds noise into the sampling "
- "process (it should be avoided to use jitter in "
- "animation)",
- default=False,
- )
-
- jitter_amount: FloatProperty(
- name="Jitter Amount",
- description="Amount of jittering",
- min=0.0,
- max=1.0,
- soft_min=0.01,
- soft_max=1.0,
- default=1.0,
- )
-
- antialias_gamma: FloatProperty(
- name="Antialias Gamma",
- description="POV-Ray compares gamma-adjusted values for super "
- "sampling. Antialias Gamma sets the Gamma before "
- "comparison",
- min=0.0,
- max=5.0,
- soft_min=0.01,
- soft_max=2.5,
- default=2.5,
- )
-
- alpha_mode: EnumProperty(
- name="Alpha",
- description="Representation of alpha information in the RGBA pixels",
- items=(
- ("SKY", "Sky", "Transparent pixels are filled with sky color"),
- (
- "TRANSPARENT",
- "Transparent",
- "Transparent, World background is transparent with premultiplied alpha",
- ),
- ),
- default="SKY",
- )
-
- use_shadows: BoolProperty(
- name="Shadows",
- description="Calculate shadows while rendering",
- default=True,
- )
-
- max_trace_level: IntProperty(
- name="Max Trace Level",
- description="Number of reflections/refractions allowed on ray "
- "path",
- min=1,
- max=256,
- default=5
- )
-
- adc_bailout_enable: BoolProperty(
- name="Enable",
- description="",
- default=False,
- )
-
- adc_bailout: FloatProperty(
- name="ADC Bailout",
- description="Adaptive Depth Control (ADC) to stop computing additional"
- "reflected or refracted rays when their contribution is insignificant."
- "The default value is 1/255, or approximately 0.0039, since a change "
- "smaller than that could not be visible in a 24 bit image. Generally "
- "this value is fine and should be left alone."
- "Setting adc_bailout to 0 will disable ADC, relying completely on "
- "max_trace_level to set an upper limit on the number of rays spawned. ",
- min=0.0,
- max=1000.0,
- default=0.00392156862745,
- precision=3
- )
-
- ambient_light_enable: BoolProperty(
- name="Enable",
- description="",
- default=False,
- )
-
- ambient_light: FloatVectorProperty(
- name="Ambient Light",
- description="Ambient light is used to simulate the effect of inter-diffuse reflection",
- precision=4, step=0.01, min=0, soft_max=1,
- default=(1, 1, 1), options={'ANIMATABLE'}, subtype='COLOR',
- )
- global_settings_advanced: BoolProperty(
- name="Advanced",
- description="",
- default=False,
- )
-
- irid_wavelength_enable: BoolProperty(
- name="Enable",
- description="",
- default=False,
- )
-
- irid_wavelength: FloatVectorProperty(
- name="Irid Wavelength",
- description=(
- "Iridescence calculations depend upon the dominant "
- "wavelengths of the primary colors of red, green and blue light"
- ),
- precision=4,
- step=0.01,
- min=0,
- soft_max=1,
- default=(0.25,0.18,0.14),
- options={'ANIMATABLE'},
- subtype='COLOR'
- )
- # Deprecated (autodetected in pov3.8):
- # charset: EnumProperty(
- # name="Charset",
- # description="This allows you to specify the assumed character set of all text strings",
- # items=(
- # ("ascii", "ASCII", ""),
- # ("utf8", "UTF-8", ""),
- # ("sys", "SYS", "")
- # ),
- # default="utf8",
- # )
-
- max_intersections_enable: BoolProperty(
- name="Enable",
- description="",
- default=False,
- )
-
- max_intersections: IntProperty(
- name="Max Intersections",
- description="POV-Ray uses a set of internal stacks to collect ray/object intersection points",
- min=2,
- max=1024,
- default=64,
- )
-
- number_of_waves_enable: BoolProperty(
- name="Enable",
- description="",
- default=False,
- )
-
- number_of_waves: IntProperty(
- name="Number Waves",
- description=(
- "The waves and ripples patterns are generated by summing a series of waves, "
- "each with a slightly different center and size"
- ),
- min=1,
- max=10,
- default=1000,
- )
-
- noise_generator_enable: BoolProperty(
- name="Enable",
- description="",
- default=False,
- )
-
- noise_generator: IntProperty(
- name="Noise Generator",
- description="There are three noise generators implemented",
- min=1,
- max=3,
- default=2,
- )
-
- ########################### PHOTONS #######################################
- photon_enable: BoolProperty(
- name="Photons",
- description="Enable global photons",
- default=False,
- )
-
- photon_enable_count: BoolProperty(
- name="Spacing / Count",
- description="Enable count photons",
- default=False,
- )
-
- photon_count: IntProperty(
- name="Count",
- description="Photons count",
- min=1,
- max=100000000,
- default=20000
- )
-
- photon_spacing: FloatProperty(
- name="Spacing",
- description="Average distance between photons on surfaces. half "
- "this get four times as many surface photons",
- min=0.001,
- max=1.000,
- soft_min=0.001,
- soft_max=1.000,
- precision=3,
- default=0.005,
- )
-
- photon_max_trace_level: IntProperty(
- name="Max Trace Level",
- description="Number of reflections/refractions allowed on ray "
- "path",
- min=1,
- max=256,
- default=5
- )
-
- photon_adc_bailout: FloatProperty(
- name="ADC Bailout",
- description="The adc_bailout for photons. Use adc_bailout = "
- "0.01 / brightest_ambient_object for good results",
- min=0.0,
- max=1000.0,
- soft_min=0.0,
- soft_max=1.0,
- precision=3,
- default=0.1,
- )
-
- photon_gather_min: IntProperty(
- name="Gather Min", description="Minimum number of photons gathered"
- "for each point",
- min=1, max=256, default=20
- )
-
- photon_gather_max: IntProperty(
- name="Gather Max", description="Maximum number of photons gathered for each point",
- min=1, max=256, default=100
- )
-
- photon_map_file_save_load: EnumProperty(
- name="Operation",
- description="Load or Save photon map file",
- items=(
- ("NONE", "None", ""),
- ("save", "Save", ""),
- ("load", "Load", "")
- ),
- default="NONE",
- )
-
- photon_map_filename: StringProperty(
- name="Filename",
- description="",
- maxlen=1024
- )
-
- photon_map_dir: StringProperty(
- name="Directory",
- description="",
- maxlen=1024,
- subtype="DIR_PATH",
- )
-
- photon_map_file: StringProperty(
- name="File",
- description="",
- maxlen=1024,
- subtype="FILE_PATH"
- )
-
- #########RADIOSITY########
- radio_adc_bailout: FloatProperty(
- name="ADC Bailout",
- description="The adc_bailout for radiosity rays. Use "
- "adc_bailout = 0.01 / brightest_ambient_object for good results",
- min=0.0,
- max=1000.0,
- soft_min=0.0,
- soft_max=1.0,
- default=0.0039,
- precision=4,
- )
-
- radio_always_sample: BoolProperty(
- name="Always Sample",
- description="Only use the data from the pretrace step and not gather "
- "any new samples during the final radiosity pass",
- default=False,
- )
-
- radio_brightness: FloatProperty(
- name="Brightness",
- description="Amount objects are brightened before being returned "
- "upwards to the rest of the system",
- min=0.0, max=1000.0, soft_min=0.0, soft_max=10.0, default=1.0
- )
-
- radio_count: IntProperty(
- name="Ray Count",
- description="Number of rays for each new radiosity value to be calculated "
- "(halton sequence over 1600)",
- min=1, max=10000, soft_max=1600, default=35
- )
-
- radio_error_bound: FloatProperty(
- name="Error Bound",
- description="One of the two main speed/quality tuning values, "
- "lower values are more accurate",
- min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default=10.0
- )
-
- radio_gray_threshold: FloatProperty(
- name="Gray Threshold",
- description="One of the two main speed/quality tuning values, "
- "lower values are more accurate",
- min=0.0, max=1.0, soft_min=0, soft_max=1, default=0.0
- )
-
- radio_low_error_factor: FloatProperty(
- name="Low Error Factor",
- description="Just enough samples is slightly blotchy. Low error changes error "
- "tolerance for less critical last refining pass",
- min=0.000001, max=1.0, soft_min=0.000001, soft_max=1.0, default=0.5
- )
-
- radio_media: BoolProperty(
- name="Media",
- description="Radiosity estimation can be affected by media",
- default=True,
- )
-
- radio_subsurface: BoolProperty(
- name="Subsurface",
- description="Radiosity estimation can be affected by Subsurface Light Transport",
- default=False,
- )
-
- radio_minimum_reuse: FloatProperty(
- name="Minimum Reuse",
- description="Fraction of the screen width which sets the minimum radius of reuse "
- "for each sample point (At values higher than 2% expect errors)",
- min=0.0, max=1.0, soft_min=0.1, soft_max=0.1, default=0.015, precision=3
- )
-
- radio_maximum_reuse: FloatProperty(
- name="Maximum Reuse",
- description="The maximum reuse parameter works in conjunction with, and is similar to that of minimum reuse, "
- "the only difference being that it is an upper bound rather than a lower one",
- min=0.0, max=1.0,default=0.2, precision=3
- )
-
- radio_nearest_count: IntProperty(
- name="Nearest Count",
- description="Number of old ambient values blended together to "
- "create a new interpolated value",
- min=1, max=20, default=1
- )
-
- radio_normal: BoolProperty(
- name="Normals",
- description="Radiosity estimation can be affected by normals",
- default=False,
- )
-
- radio_recursion_limit: IntProperty(
- name="Recursion Limit",
- description="how many recursion levels are used to calculate "
- "the diffuse inter-reflection",
- min=1, max=20, default=1
- )
-
- radio_pretrace_start: FloatProperty(
- name="Pretrace Start",
- description="Fraction of the screen width which sets the size of the "
- "blocks in the mosaic preview first pass",
- min=0.005, max=1.00, soft_min=0.02, soft_max=1.0, default=0.04
- )
- # XXX TODO set automatically to pretrace_end = 8 / max (image_width, image_height)
- # for non advanced mode
- radio_pretrace_end: FloatProperty(
- name="Pretrace End",
- description="Fraction of the screen width which sets the size of the blocks "
- "in the mosaic preview last pass",
- min=0.000925, max=1.00, soft_min=0.01, soft_max=1.00, default=0.004, precision=3
- )
-
-###############################################################################
-# Material POV properties.
-###############################################################################
-class MaterialTextureSlot(PropertyGroup):
- """Declare material texture slot level properties for UI and translated to POV."""
-
- bl_idname="pov_texture_slots",
- bl_description="Texture_slots from Blender-2.79",
-
- # Adding a "real" texture datablock as property is not possible
- # (or at least not easy through a dynamically populated EnumProperty).
- # That's why we'll use a prop_search() UILayout function in ui.py.
- # So we'll assign the name of the needed texture datablock to the below StringProperty.
- texture : StringProperty(update=active_texture_name_from_uilist)
- # and use another temporary StringProperty to change the linked data
- texture_search : StringProperty(
- name="",
- update = active_texture_name_from_search,
- description = "Browse Texture to be linked",
- )
-
- alpha_factor: FloatProperty(
- name="Alpha",
- description="Amount texture affects alpha",
- default = 1.0,
- )
-
- ambient_factor: FloatProperty(
- name="",
- description="Amount texture affects ambient",
- default = 1.0,
- )
-
- bump_method: EnumProperty(
- name="",
- description="Method to use for bump mapping",
- items=(
- ("BUMP_ORIGINAL", "Bump Original", ""),
- ("BUMP_COMPATIBLE", "Bump Compatible", ""),
- ("BUMP_DEFAULT", "Bump Default", ""),
- ("BUMP_BEST_QUALITY", "Bump Best Quality", "")
- ),
- default="BUMP_ORIGINAL",
- )
-
- bump_objectspace: EnumProperty(
- name="",
- description="Space to apply bump mapping in",
- items=(
- ("BUMP_VIEWSPACE", "Bump Viewspace", ""),
- ("BUMP_OBJECTSPACE", "Bump Objectspace", ""),
- ("BUMP_TEXTURESPACE", "Bump Texturespace", "")
- ),
- default="BUMP_VIEWSPACE",
- )
-
- density_factor: FloatProperty(
- name="",
- description="Amount texture affects density",
- default = 1.0,
- )
-
- diffuse_color_factor: FloatProperty(
- name="",
- description="Amount texture affects diffuse color",
- default = 1.0,
- )
-
- diffuse_factor: FloatProperty(
- name="",
- description="Amount texture affects diffuse reflectivity",
- default = 1.0,
- )
-
- displacement_factor: FloatProperty(
- name="",
- description="Amount texture displaces the surface",
- default = 0.2,
- )
-
- emission_color_factor: FloatProperty(
- name="",
- description="Amount texture affects emission color",
- default = 1.0,
- )
-
- emission_factor: FloatProperty(
- name="",
- description="Amount texture affects emission",
- default = 1.0,
- )
-
- emit_factor: FloatProperty(
- name="",
- description="Amount texture affects emission",
- default = 1.0,
- )
-
- hardness_factor: FloatProperty(
- name="",
- description="Amount texture affects hardness",
- default = 1.0,
- )
-
- mapping: EnumProperty(
- name="",
- description="",
- items=(("FLAT", "Flat", ""),
- ("CUBE", "Cube", ""),
- ("TUBE", "Tube", ""),
- ("SPHERE", "Sphere", "")),
- default="FLAT",
- )
-
- mapping_x: EnumProperty(
- name="",
- description="",
- items=(("NONE", "", ""),
- ("X", "", ""),
- ("Y", "", ""),
- ("Z", "", "")),
- default="NONE",
- )
-
- mapping_y: EnumProperty(
- name="",
- description="",
- items=(("NONE", "", ""),
- ("X", "", ""),
- ("Y", "", ""),
- ("Z", "", "")),
- default="NONE",
- )
-
- mapping_z: EnumProperty(
- name="",
- description="",
- items=(("NONE", "", ""),
- ("X", "", ""),
- ("Y", "", ""),
- ("Z", "", "")),
- default="NONE",
- )
-
- mirror_factor: FloatProperty(
- name="",
- description="Amount texture affects mirror color",
- default = 1.0,
- )
-
- normal_factor: FloatProperty(
- name="",
- description="Amount texture affects normal values",
- default = 1.0,
- )
-
- normal_map_space: EnumProperty(
- name="",
- description="Sets space of normal map image",
- items=(("CAMERA", "Camera", ""),
- ("WORLD", "World", ""),
- ("OBJECT", "Object", ""),
- ("TANGENT", "Tangent", "")),
- default="CAMERA",
- )
-
- object: StringProperty(
- name="Object",
- description="Object to use for mapping with Object texture coordinates",
- default ="",
- )
-
- raymir_factor: FloatProperty(
- name="",
- description="Amount texture affects ray mirror",
- default = 1.0,
- )
-
- reflection_color_factor: FloatProperty(
- name="",
- description="Amount texture affects color of out-scattered light",
- default = 1.0,
- )
-
- reflection_factor: FloatProperty(
- name="",
- description="Amount texture affects brightness of out-scattered light",
- default = 1.0,
- )
-
- scattering_factor: FloatProperty(
- name="",
- description="Amount texture affects scattering",
- default = 1.0,
- )
-
- specular_color_factor: FloatProperty(
- name="",
- description="Amount texture affects specular color",
- default = 1.0,
- )
-
- specular_factor: FloatProperty(
- name="",
- description="Amount texture affects specular reflectivity",
- default = 1.0,
- )
-
- offset: FloatVectorProperty(
- name="Offset",
- description=("Fine tune of the texture mapping X, Y and Z locations "),
- precision=4,
- step=0.1,
- soft_min= -100.0,
- soft_max=100.0,
- default=(0.0,0.0,0.0),
- options={'ANIMATABLE'},
- subtype='TRANSLATION',
- )
-
- scale: FloatVectorProperty(
- name="Size",
- subtype='XYZ',
- size=3,
- description="Set scaling for the texture’s X, Y and Z sizes ",
- precision=4,
- step=0.1,
- soft_min= -100.0,
- soft_max=100.0,
- default=(1.0,1.0,1.0),
- options={'ANIMATABLE'},
- )
-
-
- texture_coords: EnumProperty(
- name="",
- description="",
- items=(
- ("GLOBAL", "Global", ""),
- ("OBJECT", "Object", ""),
- ("UV", "UV", ""),
- ("ORCO", "Original Coordinates", ""),
- ("STRAND", "Strand", ""),
- ("STICKY", "Sticky", ""),
- ("WINDOW", "Window", ""),
- ("NORMAL", "Normal", ""),
- ("REFLECTION", "Reflection", ""),
- ("STRESS", "Stress", ""),
- ("TANGENT", "Tangent", "")
- ),
- default="GLOBAL",
- )
-
- translucency_factor: FloatProperty(
- name="",
- description="Amount texture affects translucency",
- default = 1.0,
- )
-
- transmission_color_factor: FloatProperty(
- name="",
- description="Amount texture affects result color after light has been scattered/absorbed",
- default = 1.0,
- )
-
- use: BoolProperty(
- name="",
- description="Enable this material texture slot",
- default = True,
- )
-
- use_from_dupli: BoolProperty(
- name="",
- description="Dupli’s instanced from verts, faces or particles, inherit texture coordinate from their parent",
- default = False,
- )
-
- use_from_original: BoolProperty(
- name="",
- description="Dupli’s derive their object coordinates from the original objects transformation",
- default = False,
- )
-
- use_interpolation: BoolProperty(
- name="",
- description="Interpolates pixels using selected filter ",
- default = False,
- )
-
- use_map_alpha: BoolProperty(
- name="",
- description="Causes the texture to affect the alpha value",
- default = False,
- )
-
- use_map_ambient: BoolProperty(
- name="",
- description="Causes the texture to affect the value of ambient",
- default = False,
- )
-
- use_map_color_diffuse: BoolProperty(
- name="",
- description="Causes the texture to affect basic color of the material",
- default = True,
- )
-
- use_map_color_emission: BoolProperty(
- name="",
- description="Causes the texture to affect the color of emission",
- default = False,
- )
-
- use_map_color_reflection: BoolProperty(
- name="",
- description="Causes the texture to affect the color of scattered light",
- default = False,
- )
-
- use_map_color_spec: BoolProperty(
- name="",
- description="Causes the texture to affect the specularity color",
- default = False,
- )
-
- use_map_color_transmission: BoolProperty(
- name="",
- description="Causes the texture to affect the result color after other light has been scattered/absorbed",
- default = False,
- )
-
- use_map_density: BoolProperty(
- name="",
- description="Causes the texture to affect the volume’s density",
- default = False,
- )
-
- use_map_diffuse: BoolProperty(
- name="",
- description="Causes the texture to affect the value of the materials diffuse reflectivity",
- default = False,
- )
-
- use_map_displacement: BoolProperty(
- name="",
- description="Let the texture displace the surface",
- default = False,
- )
-
- use_map_emission: BoolProperty(
- name="",
- description="Causes the texture to affect the volume’s emission",
- default = False,
- )
-
- use_map_emit: BoolProperty(
- name="",
- description="Causes the texture to affect the emit value",
- default = False,
- )
-
- use_map_hardness: BoolProperty(
- name="",
- description="Causes the texture to affect the hardness value",
- default = False,
- )
-
- use_map_mirror: BoolProperty(
- name="",
- description="Causes the texture to affect the mirror color",
- default = False,
- )
-
- use_map_normal: BoolProperty(
- name="",
- description="Causes the texture to affect the rendered normal",
- default = False,
- )
-
- use_map_raymir: BoolProperty(
- name="",
- description="Causes the texture to affect the ray-mirror value",
- default = False,
- )
-
- use_map_reflect: BoolProperty(
- name="",
- description="Causes the texture to affect the reflected light’s brightness",
- default = False,
- )
-
- use_map_scatter: BoolProperty(
- name="",
- description="Causes the texture to affect the volume’s scattering",
- default = False,
- )
-
- use_map_specular: BoolProperty(
- name="",
- description="Causes the texture to affect the value of specular reflectivity",
- default = False,
- )
-
- use_map_translucency: BoolProperty(
- name="",
- description="Causes the texture to affect the translucency value",
- default = False,
- )
-
- use_map_warp: BoolProperty(
- name="",
- description="Let the texture warp texture coordinates of next channels",
- default = False,
- )
-
- uv_layer: StringProperty(
- name="",
- description="UV layer to use for mapping with UV texture coordinates",
- default = "",
- )
-
- warp_factor: FloatProperty(
- name="",
- description="Amount texture affects texture coordinates of next channels",
- default = 0.0,
- )
-
-
-#######################################
-
- blend_factor: FloatProperty(
- name="Blend",
- description="Amount texture affects color progression of the "
- "background",
- soft_min=0.0, soft_max=1.0, default=1.0,
- )
-
- horizon_factor: FloatProperty(
- name="Horizon",
- description="Amount texture affects color of the horizon"
- "",
- soft_min=0.0, soft_max=1.0, default=1.0
- )
-
- object: StringProperty(
- name="Object",
- description="Object to use for mapping with Object texture coordinates",
- default="",
- )
-
- texture_coords: EnumProperty(
- name="Coordinates",
- description="Texture coordinates used to map the texture onto the background",
- items=(
- ("VIEW", "View", "Use view vector for the texture coordinates"),
- ("GLOBAL", "Global", "Use global coordinates for the texture coordinates (interior mist)"),
- ("ANGMAP", "AngMap", "Use 360 degree angular coordinates, e.g. for spherical light probes"),
- ("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
- ("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
- ("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
- ("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates")
- ),
- default="VIEW",
- )
-
- use_map_blend: BoolProperty(
- name="Blend Map",
- description="Affect the color progression of the background",
- default=True,
- )
-
- use_map_horizon: BoolProperty(
- name="Horizon Map",
- description="Affect the color of the horizon",
- default=False,
- )
-
- use_map_zenith_down: BoolProperty(
- name="", description="Affect the color of the zenith below",
- default=False,
- )
-
- use_map_zenith_up: BoolProperty(
- name="Zenith Up Map", description="Affect the color of the zenith above",
- default=False,
- )
-
- zenith_down_factor: FloatProperty(
- name="Zenith Down",
- description="Amount texture affects color of the zenith below",
- soft_min=0.0, soft_max=1.0, default=1.0
- )
-
- zenith_up_factor: FloatProperty(
- name="Zenith Up",
- description="Amount texture affects color of the zenith above",
- soft_min=0.0, soft_max=1.0, default=1.0
- )
-
-
-# former Space properties from removed Blender Internal added below at superclass level
-# so as to be available in World, Material, Light for texture slots use
-
-bpy.types.ID.use_limited_texture_context = BoolProperty(
- name="",
- description="Use the limited version of texture user (for ‘old shading’ mode)",
- default=True,
-)
-bpy.types.ID.texture_context = EnumProperty(
- name="Texture context",
- description="Type of texture data to display and edit",
- items=(
- ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
- ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
- ('LIGHT', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
- ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
- ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
- ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5) # "Show other data textures"
- ),
- default = 'MATERIAL',
-)
-
-# bpy.types.ID.active_texture_index = IntProperty(
- # name = "Index for texture_slots",
- # default = 0,
-# )
-
-class RenderPovSettingsMaterial(PropertyGroup):
- """Declare material level properties controllable in UI and translated to POV."""
-
- ######################Begin Old Blender Internal Props#########################
- # former Space properties from removed Blender Internal
- use_limited_texture_context: BoolProperty(
- name="",
- description="Use the limited version of texture user (for ‘old shading’ mode)",
- default=True,
- )
- texture_context: EnumProperty(
- name="Texture context",
- description="Type of texture data to display and edit",
- items=(
- ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
- ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
- ('LAMP', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
- ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
- ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
- ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5) # "Show other data textures"
- ),
- default = 'MATERIAL',
- )
-
- active_texture_index: IntProperty(
- name = "Index for texture_slots",
- default = 0,
- update = brush_texture_update
- )
-
- transparency_method: EnumProperty(
- name="Specular Shader Model",
- description="Method to use for rendering transparency",
- items=(
- ("MASK", "Mask", "Mask the background"),
- ("Z_TRANSPARENCY", "Z Transparency", "Use alpha buffer for transparent faces"),
- ("RAYTRACE", "Raytrace", "Use raytracing for transparent refraction rendering")
- ),
- default="MASK",
- )
-
- use_transparency: BoolProperty(
- name="Transparency",
- description="Render material as transparent",
- default=False,
- )
-
- alpha: FloatProperty(
- name="Alpha",
- description="Alpha transparency of the material",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
- )
-
- specular_alpha: FloatProperty(
- name="Specular alpha",
- description="Alpha transparency for specular areas",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
- )
-
- ambient: FloatProperty(
- name="Ambient",
- description="Amount of global ambient color the material receives",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
- )
-
- diffuse_color: FloatVectorProperty(
- name="Diffuse color",
- description=("Diffuse color of the material"),
- precision=4, step=0.01, min=0, # max=inf, soft_max=1,
- default=(0.6,0.6,0.6), options={'ANIMATABLE'}, subtype='COLOR',
- )
-
- darkness: FloatProperty(
- name="Darkness",
- description="Minnaert darkness",
- min=0.0, max=2.0, soft_min=0.0, soft_max=2.0, default=1.0, precision=3,
- )
-
- diffuse_fresnel: FloatProperty(
- name="Diffuse fresnel",
- description="Power of Fresnel",
- min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=1.0, precision=3,
- )
-
- diffuse_fresnel_factor: FloatProperty(
- name="Diffuse fresnel factor",
- description="Blending factor of Fresnel",
- min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=0.5, precision=3,
- )
-
- diffuse_intensity: FloatProperty(
- name="Diffuse intensity",
- description="Amount of diffuse reflection multiplying color",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.8, precision=3,
- )
-
- diffuse_ramp_blend: EnumProperty(
- name="Diffuse ramp blend",
- description="Blending method of the ramp and the diffuse color",
- items=(
- ("MIX", "Mix", ""),
- ("ADD", "Add", ""),
- ("MULTIPLY", "Multiply", ""),
- ("SUBTRACT", "Subtract", ""),
- ("SCREEN", "Screen", ""),
- ("DIVIDE", "Divide", ""),
- ("DIFFERENCE", "Difference", ""),
- ("DARKEN", "Darken", ""),
- ("LIGHTEN", "Lighten", ""),
- ("OVERLAY", "Overlay", ""),
- ("DODGE", "Dodge", ""),
- ("BURN", "Burn", ""),
- ("HUE", "Hue", ""),
- ("SATURATION", "Saturation", ""),
- ("VALUE", "Value", ""),
- ("COLOR", "Color", ""),
- ("SOFT_LIGHT", "Soft light", ""),
- ("LINEAR_LIGHT", "Linear light", "")
- ),
- default="MIX",
- )
-
- diffuse_ramp_factor: FloatProperty(
- name="Factor",
- description="Blending factor (also uses alpha in Colorband)",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
- )
-
- diffuse_ramp_input: EnumProperty(
- name="Input",
- description="How the ramp maps on the surface",
- items=(
- ("SHADER", "Shader", ""),
- ("ENERGY", "Energy", ""),
- ("NORMAL", "Normal", ""),
- ("RESULT", "Result", "")
- ),
- default="SHADER",
- )
-
- diffuse_shader: EnumProperty(
- name="Diffuse Shader Model",
- description="How the ramp maps on the surface",
- items=(
- ("LAMBERT", "Lambert", "Use a Lambertian shader"),
- ("OREN_NAYAR", "Oren-Nayar", "Use an Oren-Nayar shader"),
- ("MINNAERT", "Minnaert", "Use a Minnaert shader"),
- ("FRESNEL", "Fresnel", "Use a Fresnel shader")
- ),
- default="LAMBERT",
- )
-
- diffuse_toon_size: FloatProperty(
- name="Size",
- description="Size of diffuse toon area",
- min=0.0, max=3.14, soft_min=0.0, soft_max=3.14, default=0.5, precision=3,
- )
-
- diffuse_toon_smooth: FloatProperty(
- name="Smooth",
- description="Smoothness of diffuse toon area",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.1, precision=3,
- )
-
- emit: FloatProperty(
- name="Emit",
- description="Amount of light to emit",
- min=0.0, soft_min=0.0, # max=inf, soft_max=inf,
- default=0.0, precision=3,
- )
-
- mirror_color: FloatVectorProperty(
- name="Mirror color",
- description=("Mirror color of the material"),
- precision=4, step=0.01, min=0, # max=inf, soft_max=1,
- default=(0.6,0.6,0.6), options={'ANIMATABLE'}, subtype='COLOR'
- )
-
- roughness: FloatProperty(
- name="Roughness",
- description="Oren-Nayar Roughness",
- min=0.0, max=3.14, soft_min=0.0, soft_max=3.14,
- precision=3,
- default=0.5,
- )
-
- halo: BoolProperty(
- name="Halo",
- description=" Halo settings for the material",
- default=False,
- )
- # (was readonly in Blender2.79, never None)
-
- line_color: FloatVectorProperty(
- name="Line color",
- description=("Line color used for Freestyle line rendering"),
- precision=4, step=0.01, min=0, # max=inf, soft_max=1,
- default=(0.0,0.0,0.0), options={'ANIMATABLE'}, subtype='COLOR'
- )
-
- # diffuse_ramp:
- ## Color ramp used to affect diffuse shading
- ## Type: ColorRamp, (readonly)
-
- # cr_node = bpy.data.materials['Material'].node_tree.nodes['ColorRamp']
- # layout.template_color_ramp(cr_node, "color_ramp", expand=True)
-
- # ou
-
- # class bpy.types.ColorRamp(bpy_struct)
-
- line_priority: IntProperty(
- name="Recursion Limit",
- description="The line color of a higher priority is used at material boundaries",
- min=0, max=32767, default=0,
- )
-
- specular_color: FloatVectorProperty(
- name="Specular color",
- description=("Specular color of the material "),
- precision=4, step=0.01, min=0, # max=inf, soft_max=1,
- default=(1.0,1.0,1.0), options={'ANIMATABLE'}, subtype='COLOR'
- )
-
- specular_hardness: IntProperty(
- name="Hardness",
- description="How hard (sharp) the specular reflection is",
- min=1, max=511, default=50,
- )
-
- specular_intensity: FloatProperty(
- name="Intensity",
- description="How intense (bright) the specular reflection is",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.5, precision=3
- )
-
- specular_ior: FloatProperty(
- name="IOR",
- description="Specular index of refraction",
- min=-10.0, max=10.0, soft_min=0.0, soft_max=10.0, default=1.0, precision=3
- )
-
- ior: FloatProperty(
- name="IOR",
- description="Index of refraction",
- min=-10.0, max=10.0, soft_min=0.0, soft_max=10.0, default=1.0, precision=3
- )
-
- specular_shader: EnumProperty(
- name="Specular Shader Model",
- description="How the ramp maps on the surface",
- items=(
- ("COOKTORR", "CookTorr", "Use a Cook-Torrance shader"),
- ("PHONG", "Phong", "Use a Phong shader"),
- ("BLINN", "Blinn", "Use a Blinn shader"),
- ("TOON", "Toon", "Use a Toon shader"),
- ("WARDISO", "WardIso", "Use a Ward anisotropic shader")
- ),
- default="COOKTORR",
- )
-
- specular_slope: FloatProperty(
- name="Slope",
- description="The standard deviation of surface slope",
- min=0.0, max=0.4, soft_min=0.0, soft_max=0.4, default=0.1, precision=3
- )
-
- specular_toon_size: FloatProperty(
- name="Size",
- description="Size of specular toon area",
- min=0.0, max=0.53, soft_min=0.0, soft_max=0.53, default=0.5, precision=3
- )
-
- specular_toon_smooth: FloatProperty(
- name="Smooth",
- description="Smoothness of specular toon area",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.1, precision=3
- )
-
-
- translucency: FloatProperty(
- name="Translucency",
- description="Amount of diffuse shading on the back side",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.0, precision=3
- )
-
- transparency_method: EnumProperty(
- name="Specular Shader Model",
- description="Method to use for rendering transparency",
- items=(
- ("MASK", "Mask", "Mask the background"),
- ("Z_TRANSPARENCY", "Z Transparency", "Use an ior of 1 for transparent faces"),
- ("RAYTRACE", "Raytrace", "Use raytracing for transparent refraction rendering")
- ),
- default="MASK",
- )
-
- type: EnumProperty(
- name="Type",
- description="Material type defining how the object is rendered",
- items=(
- ("SURFACE", "Surface", "Render object as a surface"),
- ("WIRE", "Wire", "Render the edges of faces as wires (not supported in raytracing)"),# TO UPDATE > USE MACRO AND CHANGE DESCRIPTION
- ("VOLUME", "Volume", "Render object as a volume"),
- ("‘HALO’", "Halo", "Render object as halo particles")
- ), # TO UPDATE > USE MACRO AND CHANGE DESCRIPTION
- default="SURFACE",
- )
-
- use_cast_shadows: BoolProperty(
- name="Cast",
- description="Allow this material to cast shadows",
- default=True,
- )
-
- use_cast_shadows_only: BoolProperty(
- name="Cast Only",
- description="Make objects with this material "
- "appear invisible (not rendered), only "
- "casting shadows",
- default=False,
- )
-
- use_cubic: BoolProperty(
- name="Cubic Interpolation",
- description="Use cubic interpolation for diffuse "
- "values, for smoother transitions",
- default=False,
- )
-
- use_diffuse_ramp: BoolProperty(
- name="Ramp",
- description="Toggle diffuse ramp operations",
- default=False,
- )
-
- use_light_group_exclusive: BoolProperty(
- name="Exclusive",
- description="Material uses the light group exclusively"
- "- these lamps are excluded from other "
- "scene lighting",
- default=False,
- )
-
- use_light_group_local: BoolProperty(
- name="Local",
- description="When linked in, material uses local light"
- " group with the same name",
- default=False,
- )
-
- use_mist: BoolProperty(
- name="Use Mist",
- description="Use mist with this material "
- "(in world settings)",
- default=True,
- )
-
- use_nodes: BoolProperty(
- name="Nodes",
- description="Use shader nodes to render the material",# Add Icon in UI or here? icon='NODES'
- default=False,
- )
-
- use_object_color: BoolProperty(
- name="Object Color",
- description="Modulate the result with a per-object color",
- default=False,
- )
-
- use_only_shadow: BoolProperty(
- name="Shadows Only",
- description="Render shadows as the material’s alpha "
- "value, making the material transparent "
- "except for shadowed areas",
- default=False,
- )
-
- use_shadeless: BoolProperty(
- name="Shadeless",
- description="Make this material insensitive to "
- "light or shadow",
- default=False,
- )
-
- use_shadows: BoolProperty(
- name="Receive",
- description="Allow this material to receive shadows",
- default=True,
- )
-
- use_sky: BoolProperty(
- name="Sky",
- description="Render this material with zero alpha, "
- "with sky background in place (scanline only)",
- default=False,
- )
-
- use_specular_ramp: BoolProperty(
- name="Ramp",
- description="Toggle specular ramp operations",
- default=False,
- )
-
- use_tangent_shading: BoolProperty(
- name="Tangent Shading",
- description="Use the material’s tangent vector instead"
- "of the normal for shading - for "
- "anisotropic shading effects",
- default=False,
- )
-
- use_transparent_shadows: BoolProperty(
- name="Receive Transparent",
- description="Allow this object to receive transparent "
- "shadows cast through other object",
- default=False,
- ) # linked to fake caustics
-
- use_vertex_color_light: BoolProperty(
- name="Vertex Color Light",
- description="Add vertex colors as additional lighting",
- default=False,
- )
-
- use_vertex_color_paint: BoolProperty(
- name="Vertex Color Paint", description="Replace object base color with vertex "
- "colors (multiply with ‘texture face’ "
- "face assigned textures)",
- default=False,
- )
-
-
- specular_ramp_blend: EnumProperty(
- name="Specular ramp blend",
- description="Blending method of the ramp and the specular color",
- items=(
- ("MIX", "Mix", ""),
- ("ADD", "Add", ""),
- ("MULTIPLY", "Multiply", ""),
- ("SUBTRACT", "Subtract", ""),
- ("SCREEN", "Screen", ""),
- ("DIVIDE", "Divide", ""),
- ("DIFFERENCE", "Difference", ""),
- ("DARKEN", "Darken", ""),
- ("LIGHTEN", "Lighten", ""),
- ("OVERLAY", "Overlay", ""),
- ("DODGE", "Dodge", ""),
- ("BURN", "Burn", ""),
- ("HUE", "Hue", ""),
- ("SATURATION", "Saturation", ""),
- ("VALUE", "Value", ""),
- ("COLOR", "Color", ""),
- ("SOFT_LIGHT", "Soft light", ""),
- ("LINEAR_LIGHT", "Linear light", "")
- ),
- default="MIX",
- )
-
- specular_ramp_factor: FloatProperty(
- name="Factor",
- description="Blending factor (also uses alpha in Colorband)",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3,
- )
-
- specular_ramp_input: EnumProperty(
- name="Input",
- description="How the ramp maps on the surface",
- items=(
- ("SHADER", "Shader", ""),
- ("ENERGY", "Energy", ""),
- ("NORMAL", "Normal", ""),
- ("RESULT", "Result", "")
- ),
- default="SHADER",
- )
-
-
- irid_enable: BoolProperty(
- name="Iridescence coating",
- description="Newton's thin film interference (like an oil slick on a puddle of "
- "water or the rainbow hues of a soap bubble.)",
- default=False,
- )
-
- mirror_use_IOR: BoolProperty(
- name="Correct Reflection",
- description="Use same IOR as raytrace transparency to calculate mirror reflections. "
- "More physically correct",
- default=False,
- )
-
- mirror_metallic: BoolProperty(
- name="Metallic Reflection",
- description="mirror reflections get colored as diffuse (for metallic materials)",
- default=False,
- )
-
- conserve_energy: BoolProperty(
- name="Conserve Energy",
- description="Light transmitted is more correctly reduced by mirror reflections, "
- "also the sum of diffuse and translucency gets reduced below one ",
- default=True,
- )
-
- irid_amount: FloatProperty(
- name="amount",
- description="Contribution of the iridescence effect to the overall surface color. "
- "As a rule of thumb keep to around 0.25 (25% contribution) or less, "
- "but experiment. If the surface is coming out too white, try lowering "
- "the diffuse and possibly the ambient values of the surface",
- min=0.0, max=1.0, soft_min=0.01, soft_max=1.0, default=0.25,
- )
-
- irid_thickness: FloatProperty(
- name="thickness",
- description="A very thin film will have a high frequency of color changes while a "
- "thick film will have large areas of color",
- min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default=1,
- )
-
- irid_turbulence: FloatProperty(
- name="turbulence",
- description="This parameter varies the thickness",
- min=0.0, max=10.0, soft_min=0.000, soft_max=1.0, default=0
- )
-
- interior_fade_color: FloatVectorProperty(
- name="Interior Fade Color",
- description="Color of filtered attenuation for transparent "
- "materials",
- precision=4, step=0.01, min=0.0, soft_max=1.0,
- default=(0, 0, 0), options={'ANIMATABLE'}, subtype='COLOR'
- )
-
- caustics_enable: BoolProperty(
- name="Caustics",
- description="use only fake refractive caustics (default) or photon based "
- "reflective/refractive caustics",
- default=True,
- )
-
- fake_caustics: BoolProperty(
- name="Fake Caustics",
- description="use only (Fast) fake refractive caustics",
- default=True,
- )
-
- fake_caustics_power: FloatProperty(
- name="Fake caustics power",
- description="Values typically range from 0.0 to 1.0 or higher. Zero is no caustics. "
- "Low, non-zero values give broad hot-spots while higher values give "
- "tighter, smaller simulated focal points",
- min=0.00, max=10.0, soft_min=0.00, soft_max=5.0, default=0.15
- )
-
- refraction_caustics: BoolProperty(
- name="Refractive Caustics",
- description="hotspots of light focused when going through the material",
- default=True,
- )
-
- photons_dispersion: FloatProperty(
- name="Chromatic Dispersion",
- description="Light passing through will be separated according to wavelength. "
- "This ratio of refractive indices for violet to red controls how much "
- "the colors are spread out 1 = no dispersion, good values are 1.01 to 1.1",
- min=1.0000, max=10.000, soft_min=1.0000, soft_max=1.1000, precision=4,
- default=1.0000,
- )
-
- photons_dispersion_samples: IntProperty(
- name="Dispersion Samples",
- description="Number of color-steps for dispersion",
- min=2, max=128, default=7,
- )
-
- photons_reflection: BoolProperty(
- name="Reflective Photon Caustics",
- description="Use this to make your Sauron's ring ;-P",
- default=False,
- )
-
- refraction_type: EnumProperty(
- items=[
- ("1", "Z Transparency Fake Caustics", "use fake caustics"),
- ("2", "Raytrace Photons Caustics", "use photons for refractive caustics")],
- name="Refraction Type:",
- description="use fake caustics (fast) or true photons for refractive Caustics",
- default="1",
- )
-
- ##################################CustomPOV Code############################
- replacement_text: StringProperty(
- name="Declared name:",
- description="Type the declared name in custom POV code or an external "
- ".inc it points at. texture {} expected",
- default="",
- )
-
-
- # NODES
-
- def use_material_nodes_callback(self, context):
- if hasattr(context.space_data, "tree_type"):
- context.space_data.tree_type = 'ObjectNodeTree'
- mat=context.object.active_material
- if mat.pov.material_use_nodes:
- mat.use_nodes=True
- tree = mat.node_tree
- tree.name=mat.name
- links = tree.links
- default = True
- if len(tree.nodes) == 2:
- o = 0
- m = 0
- for node in tree.nodes:
- if node.type in {"OUTPUT","MATERIAL"}:
- tree.nodes.remove(node)
- default = True
- for node in tree.nodes:
- if node.bl_idname == 'PovrayOutputNode':
- o+=1
- if node.bl_idname == 'PovrayTextureNode':
- m+=1
- if o == 1 and m == 1:
- default = False
- elif len(tree.nodes) == 0:
- default = True
- else:
- default = False
- if default:
- output = tree.nodes.new('PovrayOutputNode')
- output.location = 200,200
- tmap = tree.nodes.new('PovrayTextureNode')
- tmap.location = 0,200
- links.new(tmap.outputs[0],output.inputs[0])
- tmap.select = True
- tree.nodes.active = tmap
- else:
- mat.use_nodes=False
-
-
- def use_texture_nodes_callback(self, context):
- tex=context.object.active_material.active_texture
- if tex.pov.texture_use_nodes:
- tex.use_nodes=True
- if len(tex.node_tree.nodes)==2:
- for node in tex.node_tree.nodes:
- if node.type in {"OUTPUT","CHECKER"}:
- tex.node_tree.nodes.remove(node)
- else:
- tex.use_nodes=False
-
- def node_active_callback(self, context):
- items = []
- mat=context.material
- mat.node_tree.nodes
- for node in mat.node_tree.nodes:
- node.select=False
- for node in mat.node_tree.nodes:
- if node.name==mat.pov.material_active_node:
- node.select=True
- mat.node_tree.nodes.active=node
-
- return node
-
- def node_enum_callback(self, context):
- items = []
- mat=context.material
- nodes=mat.node_tree.nodes
- for node in nodes:
- items.append(("%s"%node.name,"%s"%node.name,""))
- return items
-
- def pigment_normal_callback(self, context):
- render = context.scene.pov.render
- items = [("pigment", "Pigment", ""),("normal", "Normal", "")]
- if render == 'hgpovray':
- items = [("pigment", "Pigment", ""),("normal", "Normal", ""),("modulation", "Modulation", "")]
- return items
-
- def glow_callback(self, context):
- scene = context.scene
- ob = context.object
- ob.pov.mesh_write_as_old = ob.pov.mesh_write_as
- if scene.pov.render == 'uberpov' and ob.pov.glow:
- ob.pov.mesh_write_as = 'NONE'
- else:
- ob.pov.mesh_write_as = ob.pov.mesh_write_as_old
-
- material_use_nodes: BoolProperty(
- name="Use nodes",
- description="",
- update=use_material_nodes_callback,
- default=False,
- )
-
- material_active_node: EnumProperty(
- name="Active node",
- description="",
- items=node_enum_callback,
- update=node_active_callback
- )
-
- preview_settings: BoolProperty(
- name="Preview Settings",
- description="",
- default=False,
- )
-
- object_preview_transform: BoolProperty(
- name="Transform object",
- description="",
- default=False,
- )
-
- object_preview_scale: FloatProperty(
- name="XYZ",
- min=0.5,
- max=2.0,
- default=1.0,
- )
-
- object_preview_rotate: FloatVectorProperty(
- name="Rotate",
- description="",
- min=-180.0,
- max=180.0,
- default=(0.0,0.0,0.0),
- subtype='XYZ',
- )
-
- object_preview_bgcontrast: FloatProperty(
- name="Contrast",
- min=0.0,
- max=1.0,
- default=0.5,
- )
-
-
-class MaterialRaytraceTransparency(PropertyGroup):
- """Declare transparency panel properties controllable in UI and translated to POV."""
-
- depth: IntProperty(
- name="Depth",
- description="Maximum allowed number of light inter-refractions",
- min=0, max=32767, default=2
- )
-
- depth_max: FloatProperty(
- name="Depth",
- description="Maximum depth for light to travel through the "
- "transparent material before becoming fully filtered (0.0 is disabled)",
- min=0, max=100, default=0.0,
- )
-
- falloff: FloatProperty(
- name="Falloff",
- description="Falloff power for transmissivity filter effect (1.0 is linear)",
- min=0.1, max=10.0, default=1.0, precision=3
- )
-
- filter: FloatProperty(
- name="Filter",
- description="Amount to blend in the material’s diffuse color in raytraced "
- "transparency (simulating absorption)",
- min=0.0, max=1.0, default=0.0, precision=3
- )
-
- fresnel: FloatProperty(
- name="Fresnel",
- description="Power of Fresnel for transparency (Ray or ZTransp)",
- min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=0.0, precision=3
- )
-
- fresnel_factor: FloatProperty(
- name="Blend",
- description="Blending factor for Fresnel",
- min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=1.250, precision=3
- )
-
- gloss_factor: FloatProperty(
- name="Amount",
- description="The clarity of the refraction. "
- "(values < 1.0 give diffuse, blurry refractions)",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
- )
-
- gloss_samples: IntProperty(
- name="Samples",
- description="frequency of the noise sample used for blurry refractions",
- min=0, max=1024, default=18
- )
-
- gloss_threshold: FloatProperty(
- name="Threshold",
- description="Threshold for adaptive sampling (if a sample "
- "contributes less than this amount [as a percentage], "
- "sampling is stopped)",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.005, precision=3
- )
-
- ior: FloatProperty(
- name="IOR",
- description="Sets angular index of refraction for raytraced refraction",
- min=-0.0, max=10.0, soft_min=0.25, soft_max=4.0, default=1.3
- )
-
-class MaterialRaytraceMirror(PropertyGroup):
- """Declare reflection panel properties controllable in UI and translated to POV."""
-
- bl_description = "Raytraced reflection settings for the Material",
-
- use: BoolProperty(
- name="Mirror",
- description="Enable raytraced reflections",
- default=False,
- )
-
-
- depth: IntProperty(
- name="Depth",
- description="Maximum allowed number of light inter-reflections",
- min=0, max=32767, default=2
- )
-
- distance: FloatProperty(
- name="Max Dist",
- description="Maximum distance of reflected rays "
- "(reflections further than this range "
- "fade to sky color or material color)",
- min=0.0, max=100000.0, soft_min=0.0, soft_max=10000.0, default=0.0, precision=3
- )
-
- fade_to: EnumProperty(
- items=[
- ("FADE_TO_SKY", "Fade to sky", ""),
- ("FADE_TO_MATERIAL", "Fade to material color", "")],
- name="Fade-out Color",
- description="The color that rays with no intersection within the "
- "Max Distance take (material color can be best for "
- "indoor scenes, sky color for outdoor)",
- default="FADE_TO_SKY",
- )
-
- fresnel: FloatProperty(
- name="Fresnel",
- description="Power of Fresnel for mirror reflection",
- min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=0.0, precision=3,
- )
-
- fresnel_factor: FloatProperty(
- name="Blend",
- description="Blending factor for Fresnel",
- min=0.0, max=5.0, soft_min=0.0, soft_max=5.0, default=1.250, precision=3
- )
-
- gloss_anisotropic: FloatProperty(
- name="Anisotropic",
- description="The shape of the reflection, from 0.0 (circular) "
- "to 1.0 (fully stretched along the tangent",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
- )
-
- gloss_factor: FloatProperty(
- name="Amount",
- description="The shininess of the reflection "
- "(values < 1.0 give diffuse, blurry reflections)",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
- )
-
- gloss_samples: IntProperty(
- name="Noise",
- description="Frequency of the noise pattern bumps averaged for blurry reflections",
- min=0, max=1024, default=18,
- )
-
- gloss_threshold: FloatProperty(
- name="Threshold",
- description="Threshold for adaptive sampling (if a sample "
- "contributes less than this amount [as a percentage], "
- "sampling is stopped)",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.005, precision=3
- )
-
- mirror_color: FloatVectorProperty(
- name="Mirror color",
- description=("Mirror color of the material"),
- precision=4, step=0.01,
- default=(1.0,1.0,1.0), options={'ANIMATABLE'}, subtype='COLOR'
- )
-
- reflect_factor: FloatProperty(
- name="Reflectivity",
- description="Amount of mirror reflection for raytrace",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
- )
-
-
-class MaterialSubsurfaceScattering(PropertyGroup):
- r"""Declare SSS/SSTL properties controllable in UI and translated to POV."""
-
- bl_description = "Subsurface scattering settings for the material",
-
- use: BoolProperty(
- name="Subsurface Scattering",
- description="Enable diffuse subsurface scatting "
- "effects in a material",
- default=False,
- )
-
- back: FloatProperty(
- name="Back",
- description="Back scattering weight",
- min=0.0, max=10.0, soft_min=0.0, soft_max=10.0, default=1.0, precision=3
- )
-
- color: FloatVectorProperty(
- name="Scattering color",
- description=("Scattering color"),
- precision=4, step=0.01,
- default=(0.604,0.604,0.604), options={'ANIMATABLE'}, subtype='COLOR'
- )
-
- color_factor: FloatProperty(
- name="Color",
- description="Blend factor for SSS colors",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3
- )
-
- error_threshold: FloatProperty(
- name="Error",
- description="Error tolerance (low values are slower and higher quality)",
- default=0.050, precision=3
- )
-
- front: FloatProperty(
- name="Front",
- description="Front scattering weight",
- min=0.0, max=2.0, soft_min=0.0, soft_max=2.0, default=1.0, precision=3
- )
-
- ior: FloatProperty(
- name="IOR",
- description="Index of refraction (higher values are denser)",
- min=-0.0, max=10.0, soft_min=0.1, soft_max=2.0, default=1.3
- )
-
- radius: FloatVectorProperty(
- name="RGB Radius",
- description=("Mean red/green/blue scattering path length"),
- precision=4, step=0.01, min=0.001,
- default=(1.0,1.0,1.0), options={'ANIMATABLE'}
- )
-
- scale: FloatProperty(
- name="Scale",
- description="Object scale factor",
- default=0.100, precision=3
- )
-
- texture_factor: FloatProperty(
- name="Texture",
- description="Texture scattering blend factor",
- min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.0, precision=3
- )
-
-
-class MaterialStrandSettings(PropertyGroup):
- """Declare strand properties controllable in UI and translated to POV."""
-
- bl_description = "Strand settings for the material",
-
- blend_distance: FloatProperty(
- name="Distance",
- description="Worldspace distance over which to blend in the surface normal",
- min=0.0, max=10.0, soft_min=0.0, soft_max=10.0, default=0.0, precision=3
- )
-
- root_size: FloatProperty(
- name="Root",
- description="Start size of strands in pixels or Blender units",
- min=0.25, default=1.0, precision=5
- )
-
- shape: FloatProperty(
- name="Shape",
- description="Positive values make strands rounder, negative ones make strands spiky",
- min=-0.9, max=0.9, default=0.0, precision=3
- )
-
- size_min: FloatProperty(
- name="Minimum",
- description="Minimum size of strands in pixels",
- min=0.001, max=10.0, default=1.0, precision=3
- )
-
- tip_size: FloatProperty(
- name="Tip",
- description="End size of strands in pixels or Blender units",
- min=0.0, default=1.0, precision=5
- )
-
- use_blender_units: BoolProperty(
- name="Blender Units",
- description="Use Blender units for widths instead of pixels",
- default=False,
- )
-
- use_surface_diffuse: BoolProperty(
- name="Surface diffuse",
- description="Make diffuse shading more similar to shading the surface",
- default=False,
- )
-
- use_tangent_shading: BoolProperty(
- name="Tangent Shading",
- description="Use direction of strands as normal for tangent-shading",
- default=True,
- )
-
- uv_layer: StringProperty(
- name="UV Layer",
- # icon="GROUP_UVS",
- description="Name of UV map to override",
- default="",
- )
-
- width_fade: FloatProperty(
- name="Width Fade",
- description="Transparency along the width of the strand",
- min=0.0, max=2.0, default=0.0, precision=3
- )
-
- # halo
-
- # Halo settings for the material
- # Type: MaterialHalo, (readonly, never None)
-
- # ambient
-
- # Amount of global ambient color the material receives
- # Type: float in [0, 1], default 0.0
-
- # darkness
-
- # Minnaert darkness
- # Type: float in [0, 2], default 0.0
-
- # diffuse_color
-
- # Diffuse color of the material
- # Type: float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
-
- # diffuse_fresnel
-
- # Power of Fresnel
- # Type: float in [0, 5], default 0.0
-
- # diffuse_fresnel_factor
-
- # Blending factor of Fresnel
- # Type: float in [0, 5], default 0.0
-
- # diffuse_intensity
-
- # Amount of diffuse reflection
- # Type: float in [0, 1], default 0.0
-
- # diffuse_ramp
-
- # Color ramp used to affect diffuse shading
- # Type: ColorRamp, (readonly)
-
- # diffuse_ramp_blend
-
- # Blending method of the ramp and the diffuse color
- # Type: enum in [‘MIX’, ‘ADD’, ‘MULTIPLY’, ‘SUBTRACT’, ‘SCREEN’, ‘DIVIDE’, ‘DIFFERENCE’, ‘DARKEN’, ‘LIGHTEN’, ‘OVERLAY’, ‘DODGE’, ‘BURN’, ‘HUE’, ‘SATURATION’, ‘VALUE’, ‘COLOR’, ‘SOFT_LIGHT’, ‘LINEAR_LIGHT’], default ‘MIX’
-
- # diffuse_ramp_factor
-
- # Blending factor (also uses alpha in Colorband)
- # Type: float in [0, 1], default 0.0
-
- # diffuse_ramp_input
-
- # How the ramp maps on the surface
- # Type: enum in [‘SHADER’, ‘ENERGY’, ‘NORMAL’, ‘RESULT’], default ‘SHADER’
-
- # diffuse_shader
-
- # LAMBERT Lambert, Use a Lambertian shader.
- # OREN_NAYAR Oren-Nayar, Use an Oren-Nayar shader.
- # TOON Toon, Use a toon shader.
- # MINNAERT Minnaert, Use a Minnaert shader.
- # FRESNEL Fresnel, Use a Fresnel shader.
-
- # Type: enum in [‘LAMBERT’, ‘OREN_NAYAR’, ‘TOON’, ‘MINNAERT’, ‘FRESNEL’], default ‘LAMBERT’
-
- # diffuse_toon_size
-
- # Size of diffuse toon area
- # Type: float in [0, 3.14], default 0.0
-
- # diffuse_toon_smooth
-
- # Smoothness of diffuse toon area
- # Type: float in [0, 1], default 0.0
-
- # emit
-
- # Amount of light to emit
- # Type: float in [0, inf], default 0.0
-
- # game_settings
-
- # Game material settings
- # Type: MaterialGameSettings, (readonly, never None)
-
- # halo
-
- # Halo settings for the material
- # Type: MaterialHalo, (readonly, never None)
-
- # invert_z
-
- # Render material’s faces with an inverted Z buffer (scanline only)
- # Type: boolean, default False
-
- # light_group
-
- # Limit lighting to lamps in this Group
- # Type: Group
-
- # line_color
-
- # Line color used for Freestyle line rendering
- # Type: float array of 4 items in [0, inf], default (0.0, 0.0, 0.0, 0.0)
-
- # line_priority
-
- # The line color of a higher priority is used at material boundaries
- # Type: int in [0, 32767], default 0
-
- # mirror_color
-
- # Mirror color of the material
- # Type: float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
-
- # node_tree
-
- # Node tree for node based materials
- # Type: NodeTree, (readonly)
-
- # offset_z
-
- # Give faces an artificial offset in the Z buffer for Z transparency
- # Type: float in [-inf, inf], default 0.0
-
- # paint_active_slot
-
- # Index of active texture paint slot
- # Type: int in [0, 32767], default 0
-
- # paint_clone_slot
-
- # Index of clone texture paint slot
- # Type: int in [0, 32767], default 0
-
- # pass_index
-
- # Index number for the “Material Index” render pass
- # Type: int in [0, 32767], default 0
-
- # physics
-
- # Game physics settings
- # Type: MaterialPhysics, (readonly, never None)
-
- # preview_render_type
-
- # Type of preview render
-
- # FLAT Flat, Flat XY plane.
- # SPHERE Sphere, Sphere.
- # CUBE Cube, Cube.
- # MONKEY Monkey, Monkey.
- # HAIR Hair, Hair strands.
- # SPHERE_A World Sphere, Large sphere with sky.
-
- # Type: enum in [‘FLAT’, ‘SPHERE’, ‘CUBE’, ‘MONKEY’, ‘HAIR’, ‘SPHERE_A’], default ‘FLAT’
-
- # raytrace_mirror
-
- # Raytraced reflection settings for the material
- # Type: MaterialRaytraceMirror, (readonly, never None)
-
- # raytrace_transparency
-
- # Raytraced transparency settings for the material
- # Type: MaterialRaytraceTransparency, (readonly, never None)
-
- # roughness
-
- # Oren-Nayar Roughness
- # Type: float in [0, 3.14], default 0.0
-
- # shadow_buffer_bias
-
- # Factor to multiply shadow buffer bias with (0 is ignore)
- # Type: float in [0, 10], default 0.0
-
- # shadow_cast_alpha
-
- # Shadow casting alpha, in use for Irregular and Deep shadow buffer
- # Type: float in [0.001, 1], default 0.0
-
- # shadow_only_type
-
- # How to draw shadows
-
- # SHADOW_ONLY_OLD Shadow and Distance, Old shadow only method.
- # SHADOW_ONLY Shadow Only, Improved shadow only method.
- # SHADOW_ONLY_SHADED Shadow and Shading, Improved shadow only method which also renders lightless areas as shadows.
-
- # Type: enum in [‘SHADOW_ONLY_OLD’, ‘SHADOW_ONLY’, ‘SHADOW_ONLY_SHADED’], default ‘SHADOW_ONLY_OLD’
-
- # shadow_ray_bias
-
- # Shadow raytracing bias to prevent terminator problems on shadow boundary
- # Type: float in [0, 0.25], default 0.0
+ from bpy.props import StringProperty, BoolProperty, EnumProperty
- # specular_color
-
- # Specular color of the material
- # Type: float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
-
- # specular_hardness
-
- # How hard (sharp) the specular reflection is
- # Type: int in [1, 511], default 0
-
- # specular_intensity
-
- # How intense (bright) the specular reflection is
- # Type: float in [0, 1], default 0.0
-
- # specular_ior
-
- # Specular index of refraction
- # Type: float in [1, 10], default 0.0
-
- # specular_ramp
-
- # Color ramp used to affect specular shading
- # Type: ColorRamp, (readonly)
-
- # specular_ramp_blend
-
- # Blending method of the ramp and the specular color
- # Type: enum in [‘MIX’, ‘ADD’, ‘MULTIPLY’, ‘SUBTRACT’, ‘SCREEN’, ‘DIVIDE’, ‘DIFFERENCE’, ‘DARKEN’, ‘LIGHTEN’, ‘OVERLAY’, ‘DODGE’, ‘BURN’, ‘HUE’, ‘SATURATION’, ‘VALUE’, ‘COLOR’, ‘SOFT_LIGHT’, ‘LINEAR_LIGHT’], default ‘MIX’
-
- # specular_ramp_factor
-
- # Blending factor (also uses alpha in Colorband)
- # Type: float in [0, 1], default 0.0
-
- # specular_ramp_input
-
- # How the ramp maps on the surface
- # Type: enum in [‘SHADER’, ‘ENERGY’, ‘NORMAL’, ‘RESULT’], default ‘SHADER’
- # specular_shader
-
- # COOKTORR CookTorr, Use a Cook-Torrance shader.
- # PHONG Phong, Use a Phong shader.
- # BLINN Blinn, Use a Blinn shader.
- # TOON Toon, Use a toon shader.
- # WARDISO WardIso, Use a Ward anisotropic shader.
-
- # Type: enum in [‘COOKTORR’, ‘PHONG’, ‘BLINN’, ‘TOON’, ‘WARDISO’], default ‘COOKTORR’
-
- # specular_slope
-
- # The standard deviation of surface slope
- # Type: float in [0, 0.4], default 0.0
-
- # specular_toon_size
-
- # Size of specular toon area
- # Type: float in [0, 1.53], default 0.0
-
- # specular_toon_smooth
-
- # Smoothness of specular toon area
- # Type: float in [0, 1], default 0.0
-
- # strand
-
- # Strand settings for the material
- # Type: MaterialStrand, (readonly, never None)
-
- # subsurface_scattering
-
- # Subsurface scattering settings for the material
- # Type: MaterialSubsurfaceScattering, (readonly, never None)
-
- # texture_paint_images
-
- # Texture images used for texture painting
- # Type: bpy_prop_collection of Image, (readonly)
-
- # texture_paint_slots
-
- # Texture slots defining the mapping and influence of textures
- # Type: bpy_prop_collection of TexPaintSlot, (readonly)
-
- # texture_slots
-
- # Texture slots defining the mapping and influence of textures
- # Type: MaterialTextureSlots bpy_prop_collection of MaterialTextureSlot, (readonly)
-
- # translucency
-
- # Amount of diffuse shading on the back side
- # Type: float in [0, 1], default 0.0
-
- # transparency_method
-
- # Method to use for rendering transparency
-
- # MASK Mask, Mask the background.
- # Z_TRANSPARENCY Z Transparency, Use alpha buffer for transparent faces.
- # RAYTRACE Raytrace, Use raytracing for transparent refraction rendering.
-
- # Type: enum in [‘MASK’, ‘Z_TRANSPARENCY’, ‘RAYTRACE’], default ‘MASK’
-
- # type
-
- # Material type defining how the object is rendered
-
- # SURFACE Surface, Render object as a surface.
- # WIRE Wire, Render the edges of faces as wires (not supported in raytracing).
- # VOLUME Volume, Render object as a volume.
- # HALO Halo, Render object as halo particles.
-
- # Type: enum in [‘SURFACE’, ‘WIRE’, ‘VOLUME’, ‘HALO’], default ‘SURFACE’
-
- # use_cast_approximate
-
- # Allow this material to cast shadows when using approximate ambient occlusion
- # Type: boolean, default False
-
- # use_cast_buffer_shadows
-
- # Allow this material to cast shadows from shadow buffer lamps
- # Type: boolean, default False
-
- # use_cast_shadows
-
- # Allow this material to cast shadows
- # Type: boolean, default False
-
- # use_cast_shadows_only
-
- # Make objects with this material appear invisible (not rendered), only casting shadows
- # Type: boolean, default False
-
- # use_cubic
-
- # Use cubic interpolation for diffuse values, for smoother transitions
- # Type: boolean, default False
-
- # use_diffuse_ramp
-
- # Toggle diffuse ramp operations
- # Type: boolean, default False
-
- # use_face_texture
-
- # Replace the object’s base color with color from UV map image textures
- # Type: boolean, default False
-
- # use_face_texture_alpha
-
- # Replace the object’s base alpha value with alpha from UV map image textures
- # Type: boolean, default False
-
- # use_full_oversampling
-
- # Force this material to render full shading/textures for all anti-aliasing samples
- # Type: boolean, default False
-
- # use_light_group_exclusive
-
- # Material uses the light group exclusively - these lamps are excluded from other scene lighting
- # Type: boolean, default False
-
- # use_light_group_local
-
- # When linked in, material uses local light group with the same name
- # Type: boolean, default False
-
- # use_mist
-
- # Use mist with this material (in world settings)
- # Type: boolean, default False
-
- # use_nodes
-
- # Use shader nodes to render the material
- # Type: boolean, default False
-
- # use_object_color
-
- # Modulate the result with a per-object color
- # Type: boolean, default False
-
- # use_only_shadow
-
- # Render shadows as the material’s alpha value, making the material transparent except for shadowed areas
- # Type: boolean, default False
-
- # use_ray_shadow_bias
-
- # Prevent raytraced shadow errors on surfaces with smooth shaded normals (terminator problem)
- # Type: boolean, default False
-
- # use_raytrace
-
- # Include this material and geometry that uses it in raytracing calculations
- # Type: boolean, default False
-
- # use_shadeless
-
- # Make this material insensitive to light or shadow
- # Type: boolean, default False
-
- # use_shadows
-
- # Allow this material to receive shadows
- # Type: boolean, default False
-
- # use_sky
-
- # Render this material with zero alpha, with sky background in place (scanline only)
- # Type: boolean, default False
-
- # use_specular_ramp
-
- # Toggle specular ramp operations
- # Type: boolean, default False
-
- # use_tangent_shading
-
- # Use the material’s tangent vector instead of the normal for shading - for anisotropic shading effects
- # Type: boolean, default False
-
- # use_textures
-
- # Enable/Disable each texture
- # Type: boolean array of 18 items, default (False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
-
- # use_transparency
-
- # Render material as transparent
- # Type: boolean, default False
-
- # use_transparent_shadows
-
- # Allow this object to receive transparent shadows cast through other objects
- # Type: boolean, default False
-
- # use_uv_project
-
- # Use to ensure UV interpolation is correct for camera projections (use with UV project modifier)
- # Type: boolean, default False
-
- # use_vertex_color_light
-
- # Add vertex colors as additional lighting
- # Type: boolean, default False
-
- # use_vertex_color_paint
-
- # Replace object base color with vertex colors (multiply with ‘texture face’ face assigned textures)
- # Type: boolean, default False
-
- # volume
-
- # Volume settings for the material
- # Type: MaterialVolume, (readonly, never None)
- '''
- (mat.type in {'SURFACE', 'WIRE', 'VOLUME'})
- "use_transparency")
-
-
-
- mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY'
-
-
-
-
- col.prop(mat, "use_raytrace")
- col.prop(mat, "use_full_oversampling")
-
- sub.prop(mat, "use_sky")
-
-
- col.prop(mat, "use_cast_shadows", text="Cast")
- col.prop(mat, "use_cast_shadows_only", text="Cast Only")
- col.prop(mat, "use_cast_buffer_shadows")
-
- sub.active = mat.use_cast_buffer_shadows
- sub.prop(mat, "shadow_cast_alpha", text="Casting Alpha")
- col.prop(mat, "use_cast_approximate")
-
-
-
- col.prop(mat, "diffuse_color", text="")
-
- sub.active = (not mat.use_shadeless)
-
- sub.prop(mat, "diffuse_intensity", text="Intensity")
-
-
- col.prop(mat, "diffuse_shader", text="")
- col.prop(mat, "use_diffuse_ramp", text="Ramp")
-
-
- if mat.diffuse_shader == 'OREN_NAYAR':
- col.prop(mat, "roughness")
- elif mat.diffuse_shader == 'MINNAERT':
- col.prop(mat, "darkness")
- elif mat.diffuse_shader == 'TOON':
-
- row.prop(mat, "diffuse_toon_size", text="Size")
- row.prop(mat, "diffuse_toon_smooth", text="Smooth")
- elif mat.diffuse_shader == 'FRESNEL':
-
- row.prop(mat, "diffuse_fresnel", text="Fresnel")
- row.prop(mat, "diffuse_fresnel_factor", text="Factor")
-
- if mat.use_diffuse_ramp:
-
- col.template_color_ramp(mat, "diffuse_ramp", expand=True)
-
-
-
- row.prop(mat, "diffuse_ramp_input", text="Input")
- row.prop(mat, "diffuse_ramp_blend", text="Blend")
-
- col.prop(mat, "diffuse_ramp_factor", text="Factor")
-
-
-
-
- col.prop(mat, "specular_color", text="")
- col.prop(mat, "specular_intensity", text="Intensity")
-
- col.prop(mat, "specular_shader", text="")
- col.prop(mat, "use_specular_ramp", text="Ramp")
-
- if mat.specular_shader in {'COOKTORR', 'PHONG'}:
- col.prop(mat, "specular_hardness", text="Hardness")
- elif mat.specular_shader == 'BLINN':
-
- row.prop(mat, "specular_hardness", text="Hardness")
- row.prop(mat, "specular_ior", text="IOR")
- elif mat.specular_shader == 'WARDISO':
- col.prop(mat, "specular_slope", text="Slope")
- elif mat.specular_shader == 'TOON':
-
- row.prop(mat, "specular_toon_size", text="Size")
- row.prop(mat, "specular_toon_smooth", text="Smooth")
-
- if mat.use_specular_ramp:
- layout.separator()
- layout.template_color_ramp(mat, "specular_ramp", expand=True)
- layout.separator()
-
- row = layout.row()
- row.prop(mat, "specular_ramp_input", text="Input")
- row.prop(mat, "specular_ramp_blend", text="Blend")
-
- layout.prop(mat, "specular_ramp_factor", text="Factor")
-
-
- class MATERIAL_PT_shading(MaterialButtonsPanel, Panel):
- bl_label = "Shading"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- mat = active_node_mat(context.material)
-
- if mat.type in {'SURFACE', 'WIRE'}:
- split = layout.split()
-
- col = split.column()
- sub = col.column()
- sub.active = not mat.use_shadeless
- sub.prop(mat, "emit")
- sub.prop(mat, "ambient")
- sub = col.column()
- sub.prop(mat, "translucency")
-
- col = split.column()
- col.prop(mat, "use_shadeless")
- sub = col.column()
- sub.active = not mat.use_shadeless
- sub.prop(mat, "use_tangent_shading")
- sub.prop(mat, "use_cubic")
-
-
- class MATERIAL_PT_transp(MaterialButtonsPanel, Panel):
- bl_label = "Transparency"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- mat = context.material
-
- if simple_material(mat):
- self.layout.prop(mat, "use_transparency", text="")
-
- def draw(self, context):
- layout = self.layout
-
- base_mat = context.material
- mat = active_node_mat(context.material)
- rayt = mat.raytrace_transparency
-
- if simple_material(base_mat):
- row = layout.row()
- row.active = mat.use_transparency
- row.prop(mat, "transparency_method", expand=True)
-
- split = layout.split()
- split.active = base_mat.use_transparency
-
- col = split.column()
- col.prop(mat, "alpha")
- row = col.row()
- row.active = (base_mat.transparency_method != 'MASK') and (not mat.use_shadeless)
- row.prop(mat, "specular_alpha", text="Specular")
-
- col = split.column()
- col.active = (not mat.use_shadeless)
- col.prop(rayt, "fresnel")
- sub = col.column()
- sub.active = (rayt.fresnel > 0.0)
- sub.prop(rayt, "fresnel_factor", text="Blend")
-
- if base_mat.transparency_method == 'RAYTRACE':
- layout.separator()
- split = layout.split()
- split.active = base_mat.use_transparency
-
- col = split.column()
- col.prop(rayt, "ior")
- col.prop(rayt, "filter")
- col.prop(rayt, "falloff")
- col.prop(rayt, "depth_max")
- col.prop(rayt, "depth")
-
- col = split.column()
- col.label(text="Gloss:")
- col.prop(rayt, "gloss_factor", text="Amount")
- sub = col.column()
- sub.active = rayt.gloss_factor < 1.0
- sub.prop(rayt, "gloss_threshold", text="Threshold")
- sub.prop(rayt, "gloss_samples", text="Samples")
-
-
- class MATERIAL_PT_mirror(MaterialButtonsPanel, Panel):
- bl_label = "Mirror"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- raym = active_node_mat(context.material).raytrace_mirror
-
- self.layout.prop(raym, "use", text="")
-
- def draw(self, context):
- layout = self.layout
-
- mat = active_node_mat(context.material)
- raym = mat.raytrace_mirror
-
- layout.active = raym.use
-
- split = layout.split()
-
- col = split.column()
- col.prop(raym, "reflect_factor")
- col.prop(mat, "mirror_color", text="")
-
- col = split.column()
- col.prop(raym, "fresnel")
- sub = col.column()
- sub.active = (raym.fresnel > 0.0)
- sub.prop(raym, "fresnel_factor", text="Blend")
-
- split = layout.split()
-
- col = split.column()
- col.separator()
- col.prop(raym, "depth")
- col.prop(raym, "distance", text="Max Dist")
- col.separator()
- sub = col.split(percentage=0.4)
- sub.active = (raym.distance > 0.0)
- sub.label(text="Fade To:")
- sub.prop(raym, "fade_to", text="")
-
- col = split.column()
- col.label(text="Gloss:")
- col.prop(raym, "gloss_factor", text="Amount")
- sub = col.column()
- sub.active = (raym.gloss_factor < 1.0)
- sub.prop(raym, "gloss_threshold", text="Threshold")
- sub.prop(raym, "gloss_samples", text="Samples")
- sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
-
-
- class MATERIAL_PT_sss(MaterialButtonsPanel, Panel):
- bl_label = "Subsurface Scattering"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- mat = active_node_mat(context.material)
- sss = mat.subsurface_scattering
-
- self.layout.active = (not mat.use_shadeless)
- self.layout.prop(sss, "use", text="")
-
- def draw(self, context):
- layout = self.layout
-
- mat = active_node_mat(context.material)
- sss = mat.subsurface_scattering
-
- layout.active = (sss.use) and (not mat.use_shadeless)
-
- row = layout.row().split()
- sub = row.row(align=True).split(align=True, percentage=0.75)
- sub.menu("MATERIAL_MT_sss_presets", text=bpy.types.MATERIAL_MT_sss_presets.bl_label)
- sub.operator("material.sss_preset_add", text="", icon='ZOOMIN')
- sub.operator("material.sss_preset_add", text="", icon='ZOOMOUT').remove_active = True
-
- split = layout.split()
-
- col = split.column()
- col.prop(sss, "ior")
- col.prop(sss, "scale")
- col.prop(sss, "color", text="")
- col.prop(sss, "radius", text="RGB Radius", expand=True)
-
- col = split.column()
- sub = col.column(align=True)
- sub.label(text="Blend:")
- sub.prop(sss, "color_factor", text="Color")
- sub.prop(sss, "texture_factor", text="Texture")
- sub.label(text="Scattering Weight:")
- sub.prop(sss, "front")
- sub.prop(sss, "back")
- col.separator()
- col.prop(sss, "error_threshold", text="Error")
-
-
- class MATERIAL_PT_halo(MaterialButtonsPanel, Panel):
- bl_label = "Halo"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- mat = context.material # don't use node material
- halo = mat.halo
-
- def number_but(layout, toggle, number, name, color):
- row = layout.row(align=True)
- row.prop(halo, toggle, text="")
- sub = row.column(align=True)
- sub.active = getattr(halo, toggle)
- sub.prop(halo, number, text=name, translate=False)
- if not color == "":
- sub.prop(mat, color, text="")
-
- split = layout.split()
-
- col = split.column()
- col.prop(mat, "alpha")
- col.prop(mat, "diffuse_color", text="")
- col.prop(halo, "seed")
-
- col = split.column()
- col.prop(halo, "size")
- col.prop(halo, "hardness")
- col.prop(halo, "add")
-
- layout.label(text="Options:")
-
- split = layout.split()
- col = split.column()
- col.prop(halo, "use_texture")
- col.prop(halo, "use_vertex_normal")
- col.prop(halo, "use_extreme_alpha")
- col.prop(halo, "use_shaded")
- col.prop(halo, "use_soft")
-
- col = split.column()
- number_but(col, "use_ring", "ring_count", iface_("Rings"), "mirror_color")
- number_but(col, "use_lines", "line_count", iface_("Lines"), "specular_color")
- number_but(col, "use_star", "star_tip_count", iface_("Star Tips"), "")
-
-
- class MATERIAL_PT_flare(MaterialButtonsPanel, Panel):
- bl_label = "Flare"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- halo = context.material.halo
-
- self.layout.prop(halo, "use_flare_mode", text="")
-
- def draw(self, context):
- layout = self.layout
-
- mat = context.material # don't use node material
- halo = mat.halo
-
- layout.active = halo.use_flare_mode
-
- split = layout.split()
-
- col = split.column()
- col.prop(halo, "flare_size", text="Size")
- col.prop(halo, "flare_boost", text="Boost")
- col.prop(halo, "flare_seed", text="Seed")
-
- col = split.column()
- col.prop(halo, "flare_subflare_count", text="Subflares")
- col.prop(halo, "flare_subflare_size", text="Subsize")
-
- '''
-#######################End Old Blender Internal Props##########################
-###############################################################################
-# Povray Nodes
-###############################################################################
-
-class PovraySocketUniversal(NodeSocket):
- bl_idname = 'PovraySocketUniversal'
- bl_label = 'Povray Socket'
- value_unlimited: bpy.props.FloatProperty(default=0.0)
- value_0_1: bpy.props.FloatProperty(min=0.0,max=1.0,default=0.0)
- value_0_10: bpy.props.FloatProperty(min=0.0,max=10.0,default=0.0)
- value_000001_10: bpy.props.FloatProperty(min=0.000001,max=10.0,default=0.0)
- value_1_9: bpy.props.IntProperty(min=1,max=9,default=1)
- value_0_255: bpy.props.IntProperty(min=0,max=255,default=0)
- percent: bpy.props.FloatProperty(min=0.0,max=100.0,default=0.0)
- def draw(self, context, layout, node, text):
- space = context.space_data
- tree = space.edit_tree
- links=tree.links
- if self.is_linked:
- value=[]
- for link in links:
- if link.from_node==node:
- inps=link.to_node.inputs
- for inp in inps:
- if inp.bl_idname=="PovraySocketFloat_0_1" and inp.is_linked:
- prop="value_0_1"
- if prop not in value:
- value.append(prop)
- if inp.bl_idname=="PovraySocketFloat_000001_10" and inp.is_linked:
- prop="value_000001_10"
- if prop not in value:
- value.append(prop)
- if inp.bl_idname=="PovraySocketFloat_0_10" and inp.is_linked:
- prop="value_0_10"
- if prop not in value:
- value.append(prop)
- if inp.bl_idname=="PovraySocketInt_1_9" and inp.is_linked:
- prop="value_1_9"
- if prop not in value:
- value.append(prop)
- if inp.bl_idname=="PovraySocketInt_0_255" and inp.is_linked:
- prop="value_0_255"
- if prop not in value:
- value.append(prop)
- if inp.bl_idname=="PovraySocketFloatUnlimited" and inp.is_linked:
- prop="value_unlimited"
- if prop not in value:
- value.append(prop)
- if len(value)==1:
- layout.prop(self, "%s"%value[0], text=text)
- else:
- layout.prop(self, "percent", text="Percent")
- else:
- layout.prop(self, "percent", text=text)
- def draw_color(self, context, node):
- return (1, 0, 0, 1)
-
-class PovraySocketFloat_0_1(NodeSocket):
- bl_idname = 'PovraySocketFloat_0_1'
- bl_label = 'Povray Socket'
- default_value: bpy.props.FloatProperty(description="Input node Value_0_1",min=0,max=1,default=0)
- def draw(self, context, layout, node, text):
- if self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text, slider=True)
-
- def draw_color(self, context, node):
- return (0.5, 0.7, 0.7, 1)
-
-class PovraySocketFloat_0_10(NodeSocket):
- bl_idname = 'PovraySocketFloat_0_10'
- bl_label = 'Povray Socket'
- default_value: bpy.props.FloatProperty(description="Input node Value_0_10",min=0,max=10,default=0)
- def draw(self, context, layout, node, text):
- if node.bl_idname == 'ShaderNormalMapNode' and node.inputs[2].is_linked:
- layout.label(text='')
- self.hide_value=True
- if self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text, slider=True)
- def draw_color(self, context, node):
- return (0.65, 0.65, 0.65, 1)
-
-class PovraySocketFloat_10(NodeSocket):
- bl_idname = 'PovraySocketFloat_10'
- bl_label = 'Povray Socket'
- default_value: bpy.props.FloatProperty(description="Input node Value_10",min=-10,max=10,default=0)
- def draw(self, context, layout, node, text):
- if node.bl_idname == 'ShaderNormalMapNode' and node.inputs[2].is_linked:
- layout.label(text='')
- self.hide_value=True
- if self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text, slider=True)
- def draw_color(self, context, node):
- return (0.65, 0.65, 0.65, 1)
-
-class PovraySocketFloatPositive(NodeSocket):
- bl_idname = 'PovraySocketFloatPositive'
- bl_label = 'Povray Socket'
- default_value: bpy.props.FloatProperty(description="Input Node Value Positive", min=0.0, default=0)
- def draw(self, context, layout, node, text):
- if self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text, slider=True)
- def draw_color(self, context, node):
- return (0.045, 0.005, 0.136, 1)
-
-class PovraySocketFloat_000001_10(NodeSocket):
- bl_idname = 'PovraySocketFloat_000001_10'
- bl_label = 'Povray Socket'
- default_value: bpy.props.FloatProperty(min=0.000001,max=10,default=0.000001)
- def draw(self, context, layout, node, text):
- if self.is_output or self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text, slider=True)
- def draw_color(self, context, node):
- return (1, 0, 0, 1)
-
-class PovraySocketFloatUnlimited(NodeSocket):
- bl_idname = 'PovraySocketFloatUnlimited'
- bl_label = 'Povray Socket'
- default_value: bpy.props.FloatProperty(default = 0.0)
- def draw(self, context, layout, node, text):
- if self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text, slider=True)
- def draw_color(self, context, node):
- return (0.7, 0.7, 1, 1)
-
-class PovraySocketInt_1_9(NodeSocket):
- bl_idname = 'PovraySocketInt_1_9'
- bl_label = 'Povray Socket'
- default_value: bpy.props.IntProperty(description="Input node Value_1_9",min=1,max=9,default=6)
- def draw(self, context, layout, node, text):
- if self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text)
- def draw_color(self, context, node):
- return (1, 0.7, 0.7, 1)
-
-class PovraySocketInt_0_256(NodeSocket):
- bl_idname = 'PovraySocketInt_0_256'
- bl_label = 'Povray Socket'
- default_value: bpy.props.IntProperty(min=0,max=255,default=0)
- def draw(self, context, layout, node, text):
- if self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text)
- def draw_color(self, context, node):
- return (0.5, 0.5, 0.5, 1)
-
-
-class PovraySocketPattern(NodeSocket):
- bl_idname = 'PovraySocketPattern'
- bl_label = 'Povray Socket'
-
- default_value: bpy.props.EnumProperty(
- name="Pattern",
- description="Select the pattern",
- items=(
- ('boxed', "Boxed", ""),
- ('brick', "Brick", ""),
- ('cells', "Cells", ""),
- ('checker', "Checker", ""),
- ('granite', "Granite", ""),
- ('leopard', "Leopard", ""),
- ('marble', "Marble", ""),
- ('onion', "Onion", ""),
- ('planar', "Planar", ""),
- ('quilted', "Quilted", ""),
- ('ripples', "Ripples", ""),
- ('radial', "Radial", ""),
- ('spherical', "Spherical", ""),
- ('spotted', "Spotted", ""),
- ('waves', "Waves", ""),
- ('wood', "Wood", ""),
- ('wrinkles', "Wrinkles", "")
- ),
- default='granite')
-
- def draw(self, context, layout, node, text):
- if self.is_output or self.is_linked:
- layout.label(text="Pattern")
- else:
- layout.prop(self, "default_value", text=text)
-
- def draw_color(self, context, node):
- return (1, 1, 1, 1)
-
-class PovraySocketColor(NodeSocket):
- bl_idname = 'PovraySocketColor'
- bl_label = 'Povray Socket'
-
- default_value: bpy.props.FloatVectorProperty(
- precision=4, step=0.01, min=0, soft_max=1,
- default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR')
-
- def draw(self, context, layout, node, text):
- if self.is_output or self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text)
-
- def draw_color(self, context, node):
- return (1, 1, 0, 1)
-
-class PovraySocketColorRGBFT(NodeSocket):
- bl_idname = 'PovraySocketColorRGBFT'
- bl_label = 'Povray Socket'
-
- default_value: bpy.props.FloatVectorProperty(
- precision=4, step=0.01, min=0, soft_max=1,
- default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR')
- f: bpy.props.FloatProperty(default = 0.0,min=0.0,max=1.0)
- t: bpy.props.FloatProperty(default = 0.0,min=0.0,max=1.0)
- def draw(self, context, layout, node, text):
- if self.is_output or self.is_linked:
- layout.label(text)
- else:
- layout.prop(self, "default_value", text=text)
-
- def draw_color(self, context, node):
- return (1, 1, 0, 1)
-
-class PovraySocketTexture(NodeSocket):
- bl_idname = 'PovraySocketTexture'
- bl_label = 'Povray Socket'
- default_value: bpy.props.IntProperty()
- def draw(self, context, layout, node, text):
- layout.label(text)
-
- def draw_color(self, context, node):
- return (0, 1, 0, 1)
-
-
-
-class PovraySocketTransform(NodeSocket):
- bl_idname = 'PovraySocketTransform'
- bl_label = 'Povray Socket'
- default_value: bpy.props.IntProperty(min=0,max=255,default=0)
- def draw(self, context, layout, node, text):
- layout.label(text)
-
- def draw_color(self, context, node):
- return (99/255, 99/255, 199/255, 1)
-
-class PovraySocketNormal(NodeSocket):
- bl_idname = 'PovraySocketNormal'
- bl_label = 'Povray Socket'
- default_value: bpy.props.IntProperty(min=0,max=255,default=0)
- def draw(self, context, layout, node, text):
- layout.label(text)
-
- def draw_color(self, context, node):
- return (0.65, 0.65, 0.65, 1)
-
-class PovraySocketSlope(NodeSocket):
- bl_idname = 'PovraySocketSlope'
- bl_label = 'Povray Socket'
- default_value: bpy.props.FloatProperty(min = 0.0, max = 1.0)
- height: bpy.props.FloatProperty(min = 0.0, max = 10.0)
- slope: bpy.props.FloatProperty(min = -10.0, max = 10.0)
- def draw(self, context, layout, node, text):
- if self.is_output or self.is_linked:
- layout.label(text)
- else:
- layout.prop(self,'default_value',text='')
- layout.prop(self,'height',text='')
- layout.prop(self,'slope',text='')
- def draw_color(self, context, node):
- return (0, 0, 0, 1)
-
-class PovraySocketMap(NodeSocket):
- bl_idname = 'PovraySocketMap'
- bl_label = 'Povray Socket'
- default_value: bpy.props.StringProperty()
- def draw(self, context, layout, node, text):
- layout.label(text)
- def draw_color(self, context, node):
- return (0.2, 0, 0.2, 1)
-
-class PovrayShaderNodeCategory(NodeCategory):
- @classmethod
- def poll(cls, context):
- return context.space_data.tree_type == 'ObjectNodeTree'
-
-class PovrayTextureNodeCategory(NodeCategory):
- @classmethod
- def poll(cls, context):
- return context.space_data.tree_type == 'TextureNodeTree'
-
-class PovraySceneNodeCategory(NodeCategory):
- @classmethod
- def poll(cls, context):
- return context.space_data.tree_type == 'CompositorNodeTree'
-
-node_categories = [
-
- PovrayShaderNodeCategory("SHADEROUTPUT", "Output", items=[
- NodeItem("PovrayOutputNode"),
- ]),
-
- PovrayShaderNodeCategory("SIMPLE", "Simple texture", items=[
- NodeItem("PovrayTextureNode"),
- ]),
-
- PovrayShaderNodeCategory("MAPS", "Maps", items=[
- NodeItem("PovrayBumpMapNode"),
- NodeItem("PovrayColorImageNode"),
- NodeItem("ShaderNormalMapNode"),
- NodeItem("PovraySlopeNode"),
- NodeItem("ShaderTextureMapNode"),
- NodeItem("ShaderNodeValToRGB"),
- ]),
-
- PovrayShaderNodeCategory("OTHER", "Other patterns", items=[
- NodeItem("PovrayImagePatternNode"),
- NodeItem("ShaderPatternNode"),
- ]),
-
- PovrayShaderNodeCategory("COLOR", "Color", items=[
- NodeItem("PovrayPigmentNode"),
- ]),
-
- PovrayShaderNodeCategory("TRANSFORM", "Transform", items=[
- NodeItem("PovrayMappingNode"),
- NodeItem("PovrayMultiplyNode"),
- NodeItem("PovrayModifierNode"),
- NodeItem("PovrayTransformNode"),
- NodeItem("PovrayValueNode"),
- ]),
-
- PovrayShaderNodeCategory("FINISH", "Finish", items=[
- NodeItem("PovrayFinishNode"),
- NodeItem("PovrayDiffuseNode"),
- NodeItem("PovraySpecularNode"),
- NodeItem("PovrayPhongNode"),
- NodeItem("PovrayAmbientNode"),
- NodeItem("PovrayMirrorNode"),
- NodeItem("PovrayIridescenceNode"),
- NodeItem("PovraySubsurfaceNode"),
- ]),
-
- PovrayShaderNodeCategory("CYCLES", "Cycles", items=[
- NodeItem("ShaderNodeAddShader"),
- NodeItem("ShaderNodeAmbientOcclusion"),
- NodeItem("ShaderNodeAttribute"),
- NodeItem("ShaderNodeBackground"),
- NodeItem("ShaderNodeBlackbody"),
- NodeItem("ShaderNodeBrightContrast"),
- NodeItem("ShaderNodeBsdfAnisotropic"),
- NodeItem("ShaderNodeBsdfDiffuse"),
- NodeItem("ShaderNodeBsdfGlass"),
- NodeItem("ShaderNodeBsdfGlossy"),
- NodeItem("ShaderNodeBsdfHair"),
- NodeItem("ShaderNodeBsdfRefraction"),
- NodeItem("ShaderNodeBsdfToon"),
- NodeItem("ShaderNodeBsdfTranslucent"),
- NodeItem("ShaderNodeBsdfTransparent"),
- NodeItem("ShaderNodeBsdfVelvet"),
- NodeItem("ShaderNodeBump"),
- NodeItem("ShaderNodeCameraData"),
- NodeItem("ShaderNodeCombineHSV"),
- NodeItem("ShaderNodeCombineRGB"),
- NodeItem("ShaderNodeCombineXYZ"),
- NodeItem("ShaderNodeEmission"),
- NodeItem("ShaderNodeExtendedMaterial"),
- NodeItem("ShaderNodeFresnel"),
- NodeItem("ShaderNodeGamma"),
- NodeItem("ShaderNodeGeometry"),
- NodeItem("ShaderNodeGroup"),
- NodeItem("ShaderNodeHairInfo"),
- NodeItem("ShaderNodeHoldout"),
- NodeItem("ShaderNodeHueSaturation"),
- NodeItem("ShaderNodeInvert"),
- NodeItem("ShaderNodeLampData"),
- NodeItem("ShaderNodeLayerWeight"),
- NodeItem("ShaderNodeLightFalloff"),
- NodeItem("ShaderNodeLightPath"),
- NodeItem("ShaderNodeMapping"),
- NodeItem("ShaderNodeMaterial"),
- NodeItem("ShaderNodeMath"),
- NodeItem("ShaderNodeMixRGB"),
- NodeItem("ShaderNodeMixShader"),
- NodeItem("ShaderNodeNewGeometry"),
- NodeItem("ShaderNodeNormal"),
- NodeItem("ShaderNodeNormalMap"),
- NodeItem("ShaderNodeObjectInfo"),
- NodeItem("ShaderNodeOutput"),
- NodeItem("ShaderNodeOutputLamp"),
- NodeItem("ShaderNodeOutputLineStyle"),
- NodeItem("ShaderNodeOutputMaterial"),
- NodeItem("ShaderNodeOutputWorld"),
- NodeItem("ShaderNodeParticleInfo"),
- NodeItem("ShaderNodeRGB"),
- NodeItem("ShaderNodeRGBCurve"),
- NodeItem("ShaderNodeRGBToBW"),
- NodeItem("ShaderNodeScript"),
- NodeItem("ShaderNodeSeparateHSV"),
- NodeItem("ShaderNodeSeparateRGB"),
- NodeItem("ShaderNodeSeparateXYZ"),
- NodeItem("ShaderNodeSqueeze"),
- NodeItem("ShaderNodeSubsurfaceScattering"),
- NodeItem("ShaderNodeTangent"),
- NodeItem("ShaderNodeTexBrick"),
- NodeItem("ShaderNodeTexChecker"),
- NodeItem("ShaderNodeTexCoord"),
- NodeItem("ShaderNodeTexEnvironment"),
- NodeItem("ShaderNodeTexGradient"),
- NodeItem("ShaderNodeTexImage"),
- NodeItem("ShaderNodeTexMagic"),
- NodeItem("ShaderNodeTexMusgrave"),
- NodeItem("ShaderNodeTexNoise"),
- NodeItem("ShaderNodeTexPointDensity"),
- NodeItem("ShaderNodeTexSky"),
- NodeItem("ShaderNodeTexVoronoi"),
- NodeItem("ShaderNodeTexWave"),
- NodeItem("ShaderNodeTexture"),
- NodeItem("ShaderNodeUVAlongStroke"),
- NodeItem("ShaderNodeUVMap"),
- NodeItem("ShaderNodeValToRGB"),
- NodeItem("ShaderNodeValue"),
- NodeItem("ShaderNodeVectorCurve"),
- NodeItem("ShaderNodeVectorMath"),
- NodeItem("ShaderNodeVectorTransform"),
- NodeItem("ShaderNodeVolumeAbsorption"),
- NodeItem("ShaderNodeVolumeScatter"),
- NodeItem("ShaderNodeWavelength"),
- NodeItem("ShaderNodeWireframe"),
- ]),
-
- PovrayTextureNodeCategory("TEXTUREOUTPUT", "Output", items=[
- NodeItem("TextureNodeValToRGB"),
- NodeItem("TextureOutputNode"),
- ]),
-
- PovraySceneNodeCategory("ISOSURFACE", "Isosurface", items=[
- NodeItem("IsoPropsNode"),
- ]),
-
- PovraySceneNodeCategory("FOG", "Fog", items=[
- NodeItem("PovrayFogNode"),
-
- ]),
- ]
-############### end nodes
-
-###############################################################################
-# Texture POV properties.
-###############################################################################
-
-class RenderPovSettingsTexture(PropertyGroup):
- """Declare texture level properties controllable in UI and translated to POV."""
-
- # former Space properties from removed Blender Internal
- active_texture_index: IntProperty(
- name = "Index for texture_slots",
- min=0,
- max=17,
- default=0,
- )
-
- use_limited_texture_context: BoolProperty(
- name="",
- description="Use the limited version of texture user (for ‘old shading’ mode)",
- default=True,
- )
-
- texture_context: EnumProperty(
- name="Texture context",
- description="Type of texture data to display and edit",
- items=(
- ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
- ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
- ('LAMP', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
- ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
- ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
- ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5), # "Show other data textures"
- ),
- default = 'MATERIAL',
- )
-
- # Custom texture gamma
- tex_gamma_enable: BoolProperty(
- name="Enable custom texture gamma",
- description="Notify some custom gamma for which texture has been precorrected "
- "without the file format carrying it and only if it differs from your "
- "OS expected standard (see pov doc)",
- default=False,
- )
-
- tex_gamma_value: FloatProperty(
- name="Custom texture gamma",
- description="value for which the file was issued e.g. a Raw photo is gamma 1.0",
- min=0.45, max=5.00, soft_min=1.00, soft_max=2.50, default=1.00
- )
-
- ##################################CustomPOV Code############################
- # commented out below if we wanted custom pov code in texture only, inside exported material:
- # replacement_text = StringProperty(
- # name="Declared name:",
- # description="Type the declared name in custom POV code or an external .inc "
- # "it points at. pigment {} expected",
- # default="")
-
- tex_pattern_type: EnumProperty(
- name="Texture_Type",
- description="Choose between Blender or POV parameters to specify texture",
- items= (
- ('agate', 'Agate', '','PLUGIN', 0),
- ('aoi', 'Aoi', '', 'PLUGIN', 1),
- ('average', 'Average', '', 'PLUGIN', 2),
- ('boxed', 'Boxed', '', 'PLUGIN', 3),
- ('bozo', 'Bozo', '', 'PLUGIN', 4),
- ('bumps', 'Bumps', '', 'PLUGIN', 5),
- ('cells', 'Cells', '', 'PLUGIN', 6),
- ('crackle', 'Crackle', '', 'PLUGIN', 7),
- ('cubic', 'Cubic', '', 'PLUGIN', 8),
- ('cylindrical', 'Cylindrical', '', 'PLUGIN', 9),
- ('density_file', 'Density', '(.df3)', 'PLUGIN', 10),
- ('dents', 'Dents', '', 'PLUGIN', 11),
- ('fractal', 'Fractal', '', 'PLUGIN', 12),
- ('function', 'Function', '', 'PLUGIN', 13),
- ('gradient', 'Gradient', '', 'PLUGIN', 14),
- ('granite', 'Granite', '', 'PLUGIN', 15),
- ('image_pattern', 'Image pattern', '', 'PLUGIN', 16),
- ('leopard', 'Leopard', '', 'PLUGIN', 17),
- ('marble', 'Marble', '', 'PLUGIN', 18),
- ('onion', 'Onion', '', 'PLUGIN', 19),
- ('pigment_pattern', 'pigment pattern', '', 'PLUGIN', 20),
- ('planar', 'Planar', '', 'PLUGIN', 21),
- ('quilted', 'Quilted', '', 'PLUGIN', 22),
- ('radial', 'Radial', '', 'PLUGIN', 23),
- ('ripples', 'Ripples', '', 'PLUGIN', 24),
- ('slope', 'Slope', '', 'PLUGIN', 25),
- ('spherical', 'Spherical', '', 'PLUGIN', 26),
- ('spiral1', 'Spiral1', '', 'PLUGIN', 27),
- ('spiral2', 'Spiral2', '', 'PLUGIN', 28),
- ('spotted', 'Spotted', '', 'PLUGIN', 29),
- ('waves', 'Waves', '', 'PLUGIN', 30),
- ('wood', 'Wood', '', 'PLUGIN', 31),
- ('wrinkles', 'Wrinkles', '', 'PLUGIN', 32),
- ('brick', "Brick", "", 'PLUGIN', 33),
- ('checker', "Checker", "", 'PLUGIN', 34),
- ('hexagon', "Hexagon", "", 'PLUGIN', 35),
- ('object', "Mesh", "", 'PLUGIN', 36),
- ('emulator', "Blender Type Emulator", "", 'SCRIPTPLUGINS', 37)
- ),
- default='emulator',
- )
-
- magnet_style: EnumProperty(
- name="Magnet style",
- description="magnet or julia",
- items=(('mandel', "Mandelbrot", ""),('julia', "Julia", "")),
- default='julia',
- )
-
- magnet_type: IntProperty(
- name="Magnet_type",
- description="1 or 2",
- min=1,
- max=2,
- default=2,
- )
-
- warp_types: EnumProperty(
- name="Warp Types",
- description="Select the type of warp",
- items=(('PLANAR', "Planar", ""), ('CUBIC', "Cubic", ""),
- ('SPHERICAL', "Spherical", ""), ('TOROIDAL', "Toroidal", ""),
- ('CYLINDRICAL', "Cylindrical", ""), ('NONE', "None", "No indentation")),
- default='NONE'
- )
-
- warp_orientation: EnumProperty(
- name="Warp Orientation",
- description="Select the orientation of warp",
- items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")),
- default='y',
- )
-
- wave_type: EnumProperty(
- name="Waves type",
- description="Select the type of waves",
- items=(('ramp', "Ramp", ""), ('sine', "Sine", ""), ('scallop', "Scallop", ""),
- ('cubic', "Cubic", ""), ('poly', "Poly", ""), ('triangle', 'Triangle', "")),
- default='ramp',
- )
-
- gen_noise: IntProperty(
- name="Noise Generators",
- description="Noise Generators",
- min=1, max=3, default=1,
- )
-
- warp_dist_exp: FloatProperty(
- name="Distance exponent",
- description="Distance exponent",
- min=0.0, max=100.0, default=1.0,
- )
-
- warp_tor_major_radius: FloatProperty(
- name="Major radius",
- description="Torus is distance from major radius",
- min=0.0, max=5.0, default=1.0,
- )
-
- warp_turbulence_x: FloatProperty(
- name="Turbulence X",
- description="Turbulence X",
- min=0.0, max=5.0, default=0.0,
- )
-
- warp_turbulence_y: FloatProperty(
- name="Turbulence Y",
- description="Turbulence Y",
- min=0.0, max=5.0, default=0.0
- )
-
- warp_turbulence_z: FloatProperty(
- name="Turbulence Z",
- description="Turbulence Z",
- min=0.0, max=5.0, default=0.0
- )
-
- modifier_octaves: IntProperty(
- name="Turbulence octaves",
- description="Turbulence octaves",
- min=1, max=10, default=1
- )
-
- modifier_lambda: FloatProperty(
- name="Turbulence lambda",
- description="Turbulence lambda",
- min=0.0, max=5.0, default=1.00
- )
-
- modifier_omega: FloatProperty(
- name="Turbulence omega",
- description="Turbulence omega",
- min=0.0, max=10.0, default=1.00
- )
-
- modifier_phase: FloatProperty(
- name="Phase",
- description="The phase value causes the map entries to be shifted so that the map "
- "starts and ends at a different place",
- min=0.0, max=2.0, default=0.0
- )
-
- modifier_frequency: FloatProperty(
- name="Frequency",
- description="The frequency keyword adjusts the number of times that a color map "
- "repeats over one cycle of a pattern",
- min=0.0, max=25.0, default=2.0
- )
-
- modifier_turbulence: FloatProperty(
- name="Turbulence",
- description="Turbulence",
- min=0.0, max=5.0, default=2.0
- )
-
- modifier_numbers: IntProperty(
- name="Numbers",
- description="Numbers",
- min=1, max=27, default=2
- )
-
- modifier_control0: IntProperty(
- name="Control0",
- description="Control0",
- min=0, max=100, default=1
- )
-
- modifier_control1: IntProperty(
- name="Control1",
- description="Control1",
- min=0, max=100, default=1
- )
-
- brick_size_x: FloatProperty(
- name="Brick size x",
- description="",
- min=0.0000, max=1.0000, default=0.2500
- )
-
- brick_size_y: FloatProperty(
- name="Brick size y",
- description="",
- min=0.0000, max=1.0000, default=0.0525
- )
-
- brick_size_z: FloatProperty(
- name="Brick size z",
- description="",
- min=0.0000, max=1.0000, default=0.1250
- )
-
- brick_mortar: FloatProperty(
- name="Mortar",
- description="Mortar",
- min=0.000, max=1.500, default=0.01
- )
-
- julia_complex_1: FloatProperty(
- name="Julia Complex 1",
- description="",
- min=0.000, max=1.500, default=0.360
- )
-
- julia_complex_2: FloatProperty(
- name="Julia Complex 2",
- description="",
- min=0.000, max=1.500, default=0.250
- )
-
- f_iter: IntProperty(
- name="Fractal Iteration",
- description="",
- min=0, max=100, default=20
- )
-
- f_exponent: IntProperty(
- name="Fractal Exponent",
- description="",
- min=2, max=33, default=2
- )
-
- f_ior: IntProperty(
- name="Fractal Interior",
- description="",
- min=1, max=6, default=1
- )
-
- f_ior_fac: FloatProperty(
- name="Fractal Interior Factor",
- description="",
- min=0.0, max=10.0, default=1.0
- )
-
- f_eor: IntProperty(
- name="Fractal Exterior",
- description="",
- min=1, max=8, default=1
- )
-
- f_eor_fac: FloatProperty(
- name="Fractal Exterior Factor",
- description="",
- min=0.0, max=10.0, default=1.0
- )
-
- grad_orient_x: IntProperty(
- name="Gradient orientation X",
- description="",
- min=0, max=1, default=0
- )
-
- grad_orient_y: IntProperty(
- name="Gradient orientation Y",
- description="",
- min=0, max=1, default=1
- )
-
- grad_orient_z: IntProperty(
- name="Gradient orientation Z",
- description="",
- min=0, max=1, default=0
- )
-
- pave_sides: EnumProperty(
- name="Pavement sides",
- description="",
- items=(
- ('3', "3", ""),
- ('4', "4", ""),
- ('6', "6", "")
- ),
- default='3'
- )
-
- pave_pat_2: IntProperty(
- name="Pavement pattern 2",
- description="maximum: 2",
- min=1, max=2, default=2
- )
-
- pave_pat_3: IntProperty(
- name="Pavement pattern 3",
- description="maximum: 3",
- min=1, max=3, default=3
- )
-
- pave_pat_4: IntProperty(
- name="Pavement pattern 4",
- description="maximum: 4",
- min=1, max=4, default=4
- )
-
- pave_pat_5: IntProperty(
- name="Pavement pattern 5",
- description="maximum: 5",
- min=1, max=5, default=5
- )
-
- pave_pat_7: IntProperty(
- name="Pavement pattern 7",
- description="maximum: 7",
- min=1, max=7, default=7
- )
-
- pave_pat_12: IntProperty(
- name="Pavement pattern 12",
- description="maximum: 12",
- min=1, max=12, default=12
- )
-
- pave_pat_22: IntProperty(
- name="Pavement pattern 22",
- description="maximum: 22",
- min=1, max=22, default=22
- )
-
- pave_pat_35: IntProperty(
- name="Pavement pattern 35",
- description="maximum: 35",
- min=1, max=35, default=35,
- )
-
- pave_tiles: IntProperty(
- name="Pavement tiles",
- description="If sides = 6, maximum tiles 5!!!",
- min=1, max=6, default=1
- )
-
- pave_form: IntProperty(
- name="Pavement form",
- description="",
- min=0, max=4, default=0
- )
-
- #########FUNCTIONS#############################################################################
- #########FUNCTIONS#############################################################################
-
- func_list: EnumProperty(
- name="Functions",
- description="Select the function for create pattern",
- items=(
- ('NONE', "None", "No indentation"),
- ("f_algbr_cyl1","Algbr cyl1",""), ("f_algbr_cyl2","Algbr cyl2",""),
- ("f_algbr_cyl3","Algbr cyl3",""), ("f_algbr_cyl4","Algbr cyl4",""),
- ("f_bicorn","Bicorn",""), ("f_bifolia","Bifolia",""),
- ("f_blob","Blob",""), ("f_blob2","Blob2",""),
- ("f_boy_surface","Boy surface",""), ("f_comma","Comma",""),
- ("f_cross_ellipsoids","Cross ellipsoids",""),
- ("f_crossed_trough","Crossed trough",""), ("f_cubic_saddle","Cubic saddle",""),
- ("f_cushion","Cushion",""), ("f_devils_curve","Devils curve",""),
- ("f_devils_curve_2d","Devils curve 2d",""),
- ("f_dupin_cyclid","Dupin cyclid",""), ("f_ellipsoid","Ellipsoid",""),
- ("f_enneper","Enneper",""), ("f_flange_cover","Flange cover",""),
- ("f_folium_surface","Folium surface",""),
- ("f_folium_surface_2d","Folium surface 2d",""), ("f_glob","Glob",""),
- ("f_heart","Heart",""), ("f_helical_torus","Helical torus",""),
- ("f_helix1","Helix1",""), ("f_helix2","Helix2",""), ("f_hex_x","Hex x",""),
- ("f_hex_y","Hex y",""), ("f_hetero_mf","Hetero mf",""),
- ("f_hunt_surface","Hunt surface",""),
- ("f_hyperbolic_torus","Hyperbolic torus",""),
- ("f_isect_ellipsoids","Isect ellipsoids",""),
- ("f_kampyle_of_eudoxus","Kampyle of eudoxus",""),
- ("f_kampyle_of_eudoxus_2d","Kampyle of eudoxus 2d",""),
- ("f_klein_bottle","Klein bottle",""),
- ("f_kummer_surface_v1","Kummer surface v1",""),
- ("f_kummer_surface_v2","Kummer surface v2",""),
- ("f_lemniscate_of_gerono","Lemniscate of gerono",""),
- ("f_lemniscate_of_gerono_2d","Lemniscate of gerono 2d",""),
- ("f_mesh1","Mesh1",""), ("f_mitre","Mitre",""),
- ("f_nodal_cubic","Nodal cubic",""), ("f_noise3d","Noise3d",""),
- ("f_noise_generator","Noise generator",""), ("f_odd","Odd",""),
- ("f_ovals_of_cassini","Ovals of cassini",""), ("f_paraboloid","Paraboloid",""),
- ("f_parabolic_torus","Parabolic torus",""), ("f_ph","Ph",""),
- ("f_pillow","Pillow",""), ("f_piriform","Piriform",""),
- ("f_piriform_2d","Piriform 2d",""), ("f_poly4","Poly4",""),
- ("f_polytubes","Polytubes",""), ("f_quantum","Quantum",""),
- ("f_quartic_paraboloid","Quartic paraboloid",""),
- ("f_quartic_saddle","Quartic saddle",""),
- ("f_quartic_cylinder","Quartic cylinder",""), ("f_r","R",""),
- ("f_ridge","Ridge",""), ("f_ridged_mf","Ridged mf",""),
- ("f_rounded_box","Rounded box",""), ("f_sphere","Sphere",""),
- ("f_spikes","Spikes",""), ("f_spikes_2d","Spikes 2d",""),
- ("f_spiral","Spiral",""), ("f_steiners_roman","Steiners roman",""),
- ("f_strophoid","Strophoid",""), ("f_strophoid_2d","Strophoid 2d",""),
- ("f_superellipsoid","Superellipsoid",""), ("f_th","Th",""),
- ("f_torus","Torus",""), ("f_torus2","Torus2",""),
- ("f_torus_gumdrop","Torus gumdrop",""), ("f_umbrella","Umbrella",""),
- ("f_witch_of_agnesi","Witch of agnesi",""),
- ("f_witch_of_agnesi_2d","Witch of agnesi 2d","")
- ),
-
- default='NONE',
- )
-
- func_x: FloatProperty(
- name="FX",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_plus_x: EnumProperty(
- name="Func plus x",
- description="",
- items=(('NONE', "None", ""), ('increase', "*", ""), ('plus', "+", "")),
- default='NONE',
- )
-
- func_y: FloatProperty(
- name="FY",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_plus_y: EnumProperty(
- name="Func plus y",
- description="",
- items=(('NONE', "None", ""), ('increase', "*", ""), ('plus', "+", "")),
- default='NONE',
- )
-
- func_z: FloatProperty(
- name="FZ",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_plus_z: EnumProperty(
- name="Func plus z",
- description="",
- items=(
- ('NONE', "None", ""),
- ('increase', "*", ""),
- ('plus', "+", "")
- ),
- default='NONE',
- )
-
- func_P0: FloatProperty(
- name="P0",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_P1: FloatProperty(
- name="P1",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_P2: FloatProperty(
- name="P2",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_P3: FloatProperty(
- name="P3",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_P4: FloatProperty(
- name="P4",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_P5: FloatProperty(
- name="P5",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_P6: FloatProperty(
- name="P6",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_P7: FloatProperty(
- name="P7",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_P8: FloatProperty(
- name="P8",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- func_P9: FloatProperty(
- name="P9",
- description="",
- min=0.0, max=25.0, default=1.0
- )
-
- #########################################
- tex_rot_x: FloatProperty(
- name="Rotate X",
- description="",
- min=-180.0, max=180.0, default=0.0
- )
-
- tex_rot_y: FloatProperty(
- name="Rotate Y",
- description="",
- min=-180.0, max=180.0, default=0.0
- )
-
- tex_rot_z: FloatProperty(
- name="Rotate Z",
- description="",
- min=-180.0, max=180.0, default=0.0
- )
-
- tex_mov_x: FloatProperty(
- name="Move X",
- description="",
- min=-100000.0, max=100000.0, default=0.0
- )
-
- tex_mov_y: FloatProperty(
- name="Move Y",
- description="",
- min=-100000.0,
- max=100000.0,
- default=0.0,
- )
-
- tex_mov_z: FloatProperty(
- name="Move Z",
- description="",
- min=-100000.0,
- max=100000.0,
- default=0.0,
- )
-
- tex_scale_x: FloatProperty(
- name="Scale X",
- description="",
- min=0.0,
- max=10000.0,
- default=1.0,
- )
-
- tex_scale_y: FloatProperty(
- name="Scale Y",
- description="",
- min=0.0,
- max=10000.0,
- default=1.0,
- )
-
- tex_scale_z: FloatProperty(
- name="Scale Z",
- description="",
- min=0.0,
- max=10000.0,
- default=1.0,
+ from . import (
+ base_ui,
+ render_properties,
+ scenography_properties,
+ shading_properties,
+ texturing_properties,
+ object_properties,
+ scripting_properties,
+ render,
+ object_primitives, # for import and export of POV specific primitives
+ update_files,
)
###############################################################################
-# Object POV properties.
+# Auto update.
###############################################################################
-
-class RenderPovSettingsObject(PropertyGroup):
- """Declare object and primitives level properties controllable in UI and translated to POV."""
-
- # Pov inside_vector used for CSG
- inside_vector: FloatVectorProperty(
- name="CSG Inside Vector",
- description="Direction to shoot CSG inside test rays at",
- precision=4,
- step=0.01,
- min=0,
- soft_max=1,
- default=(0.001, 0.001, 0.5),
- options={'ANIMATABLE'},
- subtype='XYZ'
- )
-
- # Importance sampling
- importance_value: FloatProperty(
- name="Radiosity Importance",
- description="Priority value relative to other objects for sampling radiosity rays. "
- "Increase to get more radiosity rays at comparatively small yet "
- "bright objects",
- min=0.01, max=1.00, default=0.50
- )
-
- # Collect photons
- collect_photons: BoolProperty(
- name="Receive Photon Caustics",
- description="Enable object to collect photons from other objects caustics. Turn "
- "off for objects that don't really need to receive caustics (e.g. objects"
- " that generate caustics often don't need to show any on themselves)",
- default=True,
- )
-
- # Photons spacing_multiplier
- spacing_multiplier: FloatProperty(
- name="Photons Spacing Multiplier",
- description="Multiplier value relative to global spacing of photons. "
- "Decrease by half to get 4x more photons at surface of "
- "this object (or 8x media photons than specified in the globals",
- min=0.01, max=1.00, default=1.00)
-
- ##################################CustomPOV Code############################
- # Only DUMMIES below for now:
- replacement_text: StringProperty(
- name="Declared name:",
- description="Type the declared name in custom POV code or an external .inc "
- "it points at. Any POV shape expected e.g: isosurface {}",
- default="",
- )
-
- #############POV specific object properties.############################
- object_as: StringProperty(maxlen=1024)
-
- imported_loc: FloatVectorProperty(
- name="Imported Pov location",
- precision=6,
- default=(0.0, 0.0, 0.0),
- )
-
- imported_loc_cap: FloatVectorProperty(
- name="Imported Pov location",
- precision=6,
- default=(0.0, 0.0, 2.0),
- )
-
- unlock_parameters: BoolProperty(name="Lock",default = False)
-
- # not in UI yet but used for sor (lathe) / prism... pov primitives
- curveshape: EnumProperty(
- name="Povray Shape Type",
- items=(("birail", "Birail", ""),
- ("cairo", "Cairo", ""),
- ("lathe", "Lathe", ""),
- ("loft", "Loft", ""),
- ("prism", "Prism", ""),
- ("sphere_sweep", "Sphere Sweep", "")),
- default="sphere_sweep",
- )
-
- mesh_write_as: EnumProperty(
- name="Mesh Write As",
- items=(("blobgrid", "Blob Grid", ""),
- ("grid", "Grid", ""),
- ("mesh", "Mesh", "")),
- default="mesh",
- )
-
- object_ior: FloatProperty(
- name="IOR", description="IOR",
- min=1.0, max=10.0,default=1.0
- )
-
- # shape_as_light = StringProperty(name="Light",maxlen=1024)
- # fake_caustics_power = FloatProperty(
- # name="Power", description="Fake caustics power",
- # min=0.0, max=10.0,default=0.0)
- # target = BoolProperty(name="Target",description="",default=False)
- # target_value = FloatProperty(
- # name="Value", description="",
- # min=0.0, max=1.0,default=1.0)
- # refraction = BoolProperty(name="Refraction",description="",default=False)
- # dispersion = BoolProperty(name="Dispersion",description="",default=False)
- # dispersion_value = FloatProperty(
- # name="Dispersion", description="Good values are 1.01 to 1.1. ",
- # min=1.0, max=1.2,default=1.01)
- # dispersion_samples = IntProperty(name="Samples",min=2, max=100,default=7)
- # reflection = BoolProperty(name="Reflection",description="",default=False)
- # pass_through = BoolProperty(name="Pass through",description="",default=False)
- no_shadow: BoolProperty(name="No Shadow",default=False)
-
- no_image: BoolProperty(name="No Image",default=False)
-
- no_reflection: BoolProperty(name="No Reflection",default=False)
-
- no_radiosity: BoolProperty(name="No Radiosity",default=False)
-
- inverse: BoolProperty(name="Inverse",default=False)
-
- sturm: BoolProperty(name="Sturm",default=False)
-
- double_illuminate: BoolProperty(name="Double Illuminate",default=False)
-
- hierarchy: BoolProperty(name="Hierarchy",default=False)
-
- hollow: BoolProperty(name="Hollow",default=False)
-
- boundorclip: EnumProperty(
- name="Boundorclip",
- items=(("none", "None", ""),
- ("bounded_by", "Bounded_by", ""),
- ("clipped_by", "Clipped_by", "")),
- default="none",
- )
-
- boundorclipob: StringProperty(maxlen=1024)
-
- addboundorclip: BoolProperty(description="",default=False)
-
- blob_threshold: FloatProperty(name="Threshold",min=0.00, max=10.0, default=0.6)
-
- blob_strength: FloatProperty(name="Strength",min=-10.00, max=10.0, default=1.00)
-
- res_u: IntProperty(name="U",min=100, max=1000, default=500)
-
- res_v: IntProperty(name="V",min=100, max=1000, default=500)
-
- contained_by: EnumProperty(
- name="Contained by",
- items=(("box", "Box", ""),
- ("sphere", "Sphere", "")),
- default="box",
- )
-
- container_scale: FloatProperty(name="Container Scale",min=0.0, max=10.0, default=1.00)
-
- threshold: FloatProperty(name="Threshold",min=0.0, max=10.0, default=0.00)
-
- accuracy: FloatProperty(name="Accuracy",min=0.0001, max=0.1, default=0.001)
-
- max_gradient: FloatProperty(name="Max Gradient",min=0.0, max=100.0, default=5.0)
-
- all_intersections: BoolProperty(name="All Intersections",default=False)
-
- max_trace: IntProperty(name="Max Trace",min=1, max=100,default=1)
-
-
- def prop_update_cylinder(self, context):
- """Update POV cylinder primitive parameters not only at creation but anytime they are changed in UI."""
- if bpy.ops.pov.cylinder_update.poll():
- bpy.ops.pov.cylinder_update()
-
- cylinder_radius: FloatProperty(
- name="Cylinder R",min=0.00, max=10.0, default=0.04, update=prop_update_cylinder)
-
- cylinder_location_cap: FloatVectorProperty(
- name="Cylinder Cap Location", subtype='TRANSLATION',
- description="The position of the 'other' end of the cylinder (relative to object location)",
- default=(0.0, 0.0, 2.0), update=prop_update_cylinder
- )
-
- imported_cyl_loc: FloatVectorProperty(
- name="Imported Pov location",
- precision=6,
- default=(0.0, 0.0, 0.0)
- )
-
- imported_cyl_loc_cap: FloatVectorProperty(
- name="Imported Pov location",
- precision=6,
- default=(0.0, 0.0, 2.0)
- )
-
- def prop_update_sphere(self, context):
-
- """Update POV sphere primitive parameters not only at creation but anytime they are changed in UI."""
-
- bpy.ops.pov.sphere_update()
-
- sphere_radius: FloatProperty(
- name="Sphere radius",min=0.00, max=10.0, default=0.5, update=prop_update_sphere)
-
- def prop_update_cone(self, context):
-
- """Update POV cone primitive parameters not only at creation but anytime they are changed in UI."""
-
- bpy.ops.pov.cone_update()
-
- cone_base_radius: FloatProperty(
- name = "Base radius",
- description = "The first radius of the cone",
- default = 1.0, min = 0.01, max = 100.0, update=prop_update_cone
- )
-
- cone_cap_radius: FloatProperty(
- name = "Cap radius",
- description = "The second radius of the cone",
- default = 0.3, min = 0.0, max = 100.0, update=prop_update_cone
- )
-
- cone_segments: IntProperty(
- name = "Segments",
- description = "Radial segmentation of proxy mesh",
- default = 16, min = 3, max = 265, update=prop_update_cone
- )
-
- cone_height: FloatProperty(
- name = "Height",
- description = "Height of the cone",
- default = 2.0, min = 0.01, max = 100.0, update=prop_update_cone
- )
-
- cone_base_z: FloatProperty()
-
- cone_cap_z: FloatProperty()
-
-###########Parametric
- def prop_update_parametric(self, context):
-
- """Update POV parametric surface primitive parameters not only at creation but anytime they are changed in UI."""
-
- bpy.ops.pov.parametric_update()
-
- u_min: FloatProperty(
- name = "U Min",
- description = "",
- default = 0.0, update=prop_update_parametric
- )
-
- v_min: FloatProperty(
- name = "V Min",
- description = "",
- default = 0.0,
- update=prop_update_parametric
- )
-
- u_max: FloatProperty(
- name = "U Max",
- description = "",
- default = 6.28,
- update=prop_update_parametric
- )
-
- v_max: FloatProperty(
- name = "V Max",
- description = "",
- default = 12.57, update=prop_update_parametric
- )
-
- x_eq: StringProperty(
- maxlen=1024,
- default = "cos(v)*(1+cos(u))*sin(v/8)",
- update=prop_update_parametric
- )
-
- y_eq: StringProperty(
- maxlen=1024,
- default = "sin(u)*sin(v/8)+cos(v/8)*1.5",
- update=prop_update_parametric
- )
-
- z_eq: StringProperty(
- maxlen=1024,
- default = "sin(v)*(1+cos(u))*sin(v/8)",
- update=prop_update_parametric
- )
-
- ###########Torus
-
- def prop_update_torus(self, context):
-
- """Update POV torus primitive parameters not only at creation but anytime they are changed in UI."""
-
- bpy.ops.pov.torus_update()
-
- torus_major_segments: IntProperty(
- name = "Segments",
- description = "Radial segmentation of proxy mesh",
- default = 48, min = 3, max = 720, update=prop_update_torus
- )
-
- torus_minor_segments: IntProperty(
- name = "Segments",
- description = "Cross-section segmentation of proxy mesh",
- default = 12, min = 3, max = 720, update=prop_update_torus
- )
-
- torus_major_radius: FloatProperty(
- name="Major radius",
- description="Major radius",
- min=0.00, max=100.00, default=1.0, update=prop_update_torus
- )
-
- torus_minor_radius: FloatProperty(
- name="Minor radius",
- description="Minor radius",
- min=0.00, max=100.00, default=0.25, update=prop_update_torus
- )
-
-
- ###########Rainbow
- arc_angle: FloatProperty(
- name = "Arc angle",
- description = "The angle of the raynbow arc in degrees",
- default = 360, min = 0.01, max = 360.0
- )
-
- falloff_angle: FloatProperty(
- name = "Falloff angle",
- description = "The angle after which rainbow dissolves into background",
- default = 360, min = 0.0, max = 360
- )
-
- ###########HeightFields
-
- quality: IntProperty(
- name = "Quality",
- description = "",
- default = 100, min = 1, max = 100
- )
-
- hf_filename: StringProperty(maxlen = 1024)
-
- hf_gamma: FloatProperty(
- name="Gamma",
- description="Gamma",
- min=0.0001, max=20.0, default=1.0
- )
-
- hf_premultiplied: BoolProperty(
- name="Premultiplied",
- description="Premultiplied",
- default=True,
- )
-
- hf_smooth: BoolProperty(
- name="Smooth",
- description="Smooth",
- default=False,
- )
-
- hf_water: FloatProperty(
- name="Water Level",
- description="Wather Level",
- min=0.00, max=1.00, default=0.0,
- )
-
- hf_hierarchy: BoolProperty(
- name="Hierarchy",
- description="Height field hierarchy",
- default=True,
- )
-
- ##############Superellipsoid
- def prop_update_superellipsoid(self, context):
-
- """Update POV superellipsoid primitive parameters not only at creation but anytime they are changed in UI."""
-
- bpy.ops.pov.superellipsoid_update()
-
- se_param1: FloatProperty(
- name="Parameter 1",
- description="",
- min=0.00, max=10.0, default=0.04
- )
-
- se_param2: FloatProperty(
- name="Parameter 2",
- description="",
- min=0.00, max=10.0, default=0.04
- )
-
- se_u: IntProperty(
- name = "U-segments",
- description = "radial segmentation",
- default = 20, min = 4, max = 265,
- update=prop_update_superellipsoid
- )
-
- se_v: IntProperty(
- name = "V-segments",
- description = "lateral segmentation",
- default = 20, min = 4, max = 265,
- update=prop_update_superellipsoid
- )
-
- se_n1: FloatProperty(
- name = "Ring manipulator",
- description = "Manipulates the shape of the Ring",
- default = 1.0, min = 0.01, max = 100.0,
- update=prop_update_superellipsoid
- )
-
- se_n2: FloatProperty(name = "Cross manipulator",
- description = "Manipulates the shape of the cross-section",
- default = 1.0, min = 0.01, max = 100.0,
- update=prop_update_superellipsoid
- )
-
- se_edit: EnumProperty(items=[("NOTHING", "Nothing", ""),
- ("NGONS", "N-Gons", ""),
- ("TRIANGLES", "Triangles", "")],
- name="Fill up and down",
- description="",
- default='TRIANGLES',
- update=prop_update_superellipsoid
- )
-
- #############Used for loft and Superellipsoid, etc.
- curveshape: EnumProperty(
- name="Povray Shape Type",
- items=(
- ("birail", "Birail", ""),
- ("cairo", "Cairo", ""),
- ("lathe", "Lathe", ""),
- ("loft", "Loft", ""),
- ("prism", "Prism", ""),
- ("sphere_sweep", "Sphere Sweep", ""),
- ("sor", "Surface of Revolution", "")
- ),
- default="sphere_sweep",
- )
-
-#############Supertorus
- def prop_update_supertorus(self, context):
-
- """Update POV supertorus primitive parameters not only at creation but anytime they are changed in UI."""
-
- bpy.ops.pov.supertorus_update()
-
- st_major_radius: FloatProperty(
- name="Major radius",
- description="Major radius",
- min=0.00,
- max=100.00,
- default=1.0,
- update=prop_update_supertorus
- )
-
- st_minor_radius: FloatProperty(
- name="Minor radius",
- description="Minor radius",
- min=0.00, max=100.00, default=0.25,
- update=prop_update_supertorus
- )
-
- st_ring: FloatProperty(
- name="Ring",
- description="Ring manipulator",
- min=0.0001, max=100.00, default=1.00,
- update=prop_update_supertorus
- )
-
- st_cross: FloatProperty(
- name="Cross",
- description="Cross manipulator",
- min=0.0001, max=100.00, default=1.00,
- update=prop_update_supertorus
- )
-
- st_accuracy: FloatProperty(
- name="Accuracy",
- description="Supertorus accuracy",
- min=0.00001, max=1.00, default=0.001
- )
-
- st_max_gradient: FloatProperty(
- name="Gradient",
- description="Max gradient",
- min=0.0001, max=100.00, default=10.00,
- update=prop_update_supertorus
- )
-
- st_R: FloatProperty(
- name = "big radius",
- description = "The radius inside the tube",
- default = 1.0, min = 0.01, max = 100.0,
- update=prop_update_supertorus
- )
-
- st_r: FloatProperty(
- name = "small radius",
- description = "The radius of the tube",
- default = 0.3, min = 0.01, max = 100.0,
- update=prop_update_supertorus
- )
-
- st_u: IntProperty(
- name = "U-segments",
- description = "radial segmentation",
- default = 16, min = 3, max = 265,
- update=prop_update_supertorus
- )
-
- st_v: IntProperty(
- name = "V-segments",
- description = "lateral segmentation",
- default = 8, min = 3, max = 265,
- update=prop_update_supertorus
- )
-
- st_n1: FloatProperty(
- name = "Ring manipulator",
- description = "Manipulates the shape of the Ring",
- default = 1.0, min = 0.01, max = 100.0,
- update=prop_update_supertorus
- )
-
- st_n2: FloatProperty(
- name = "Cross manipulator",
- description = "Manipulates the shape of the cross-section",
- default = 1.0, min = 0.01, max = 100.0,
- update=prop_update_supertorus
- )
-
- st_ie: BoolProperty(
- name = "Use Int.+Ext. radii",
- description = "Use internal and external radii",
- default = False,
- update=prop_update_supertorus
- )
-
- st_edit: BoolProperty(
- name="",
- description="",
- default=False,
- options={'HIDDEN'},
- update=prop_update_supertorus
- )
-
- ########################Loft
- loft_n: IntProperty(
- name = "Segments",
- description = "Vertical segments",
- default = 16, min = 3, max = 720
- )
-
- loft_rings_bottom: IntProperty(
- name = "Bottom",
- description = "Bottom rings",
- default = 5, min = 2, max = 100
- )
-
- loft_rings_side: IntProperty(
- name = "Side",
- description = "Side rings",
- default = 10, min = 2, max = 100
- )
-
- loft_thick: FloatProperty(
- name = "Thickness",
- description = "Manipulates the shape of the Ring",
- default = 0.3, min = 0.01, max = 1.0
- )
-
- loft_r: FloatProperty(
- name = "Radius",
- description = "Radius",
- default = 1, min = 0.01, max = 10
- )
-
- loft_height: FloatProperty(
- name = "Height",
- description = "Manipulates the shape of the Ring",
- default = 2, min = 0.01, max = 10.0
- )
-
- ###################Prism
- prism_n: IntProperty(
- name = "Sides",
- description = "Number of sides",
- default = 5, min = 3, max = 720
- )
-
- prism_r: FloatProperty(
- name = "Radius",
- description = "Radius",
- default = 1.0
- )
-
- ##################Isosurface
- iso_function_text: StringProperty(
- name="Function Text",
- maxlen=1024
- ) #,update=iso_props_update_callback)
-
- ##################PolygonToCircle
- polytocircle_resolution: IntProperty(
- name = "Resolution",
- description = "",
- default = 3, min = 0, max = 256
- )
-
- polytocircle_ngon: IntProperty(
- name = "NGon",
- description = "",
- min = 3, max = 64,default = 5
- )
-
- polytocircle_ngonR: FloatProperty(
- name = "NGon Radius",
- description = "",
- default = 0.3
- )
-
- polytocircle_circleR: FloatProperty(
- name = "Circle Radius",
- description = "",
- default = 1.0
- )
-
-
-###############################################################################
-# Modifiers POV properties.
-###############################################################################
-# class RenderPovSettingsModifier(PropertyGroup):
- boolean_mod: EnumProperty(
- name="Operation",
- description="Choose the type of calculation for Boolean modifier",
- items=(
- ("BMESH", "Use the BMesh Boolean Solver", ""),
- ("CARVE", "Use the Carve Boolean Solver", ""),
- ("POV", "Use POV Constructive Solid Geometry", "")
- ),
- default="BMESH",
- )
-
- #################Avogadro
- # filename_ext = ".png"
-
- # filter_glob = StringProperty(
- # default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
- # options={'HIDDEN'},
- # )
-
-###############################################################################
-# Camera POV properties.
-###############################################################################
-class RenderPovSettingsCamera(PropertyGroup):
-
- """Declare camera properties controllable in UI and translated to POV."""
-
- # DOF Toggle
- dof_enable: BoolProperty(
- name="Depth Of Field",
- description="Enable POV Depth Of Field ",
- default=False,
- )
-
- # Aperture (Intensity of the Blur)
- dof_aperture: FloatProperty(
- name="Aperture",
- description="Similar to a real camera's aperture effect over focal blur (though not "
- "in physical units and independent of focal length). "
- "Increase to get more blur",
- min=0.01, max=1.00, default=0.50
- )
-
- # Aperture adaptive sampling
- dof_samples_min: IntProperty(
- name="Samples Min",
- description="Minimum number of rays to use for each pixel",
- min=1, max=128, default=3
- )
-
- dof_samples_max: IntProperty(
- name="Samples Max",
- description="Maximum number of rays to use for each pixel",
- min=1, max=128, default=9
- )
-
- dof_variance: IntProperty(
- name="Variance",
- description="Minimum threshold (fractional value) for adaptive DOF sampling (up "
- "increases quality and render time). The value for the variance should "
- "be in the range of the smallest displayable color difference",
- min=1, max=100000, soft_max=10000, default=8192
- )
-
- dof_confidence: FloatProperty(
- name="Confidence",
- description="Probability to reach the real color value. Larger confidence values "
- "will lead to more samples, slower traces and better images",
- min=0.01, max=0.99, default=0.20
- )
-
- normal_enable: BoolProperty(
- name="Perturbated Camera",
- default=False,
- )
-
- cam_normal: FloatProperty(
- name="Normal Strength",
- min=0.0,
- max=1.0,
- default=0.0,
- )
-
- normal_patterns: EnumProperty(
- name="Pattern",
- description="",
- items=(
- ('agate', "Agate", ""),
- ('boxed', "Boxed", ""),
- ('bumps', "Bumps", ""),
- ('cells', "Cells", ""),
- ('crackle', "Crackle", ""),
- ('dents', "Dents", ""),
- ('granite', "Granite", ""),
- ('leopard', "Leopard", ""),
- ('marble', "Marble", ""),
- ('onion', "Onion", ""),
- ('pavement', "Pavement", ""),
- ('planar', "Planar", ""),
- ('quilted', "Quilted", ""),
- ('ripples', "Ripples", ""),
- ('radial', "Radial", ""),
- ('spherical', "Spherical", ""),
- ('spiral1', "Spiral1", ""),
- ('spiral2', "Spiral2", ""),
- ('spotted', "Spotted", ""),
- ('square', "Square", ""),
- ('tiling', "Tiling", ""),
- ('waves', "Waves", ""),
- ('wood', "Wood", ""),
- ('wrinkles', "Wrinkles", "")
- ),
- default='agate',
- )
-
- turbulence: FloatProperty(name="Turbulence", min=0.0, max=100.0, default=0.1)
-
- scale: FloatProperty(name="Scale", min=0.0,default=1.0)
-
- ##################################CustomPOV Code############################
- # Only DUMMIES below for now:
- replacement_text: StringProperty(
- name="Texts in blend file",
- description="Type the declared name in custom POV code or an external .inc "
- "it points at. camera {} expected",
- default="",
- )
-###############################################################################
-# Light POV properties.
-###############################################################################
-class RenderPovSettingsLight(PropertyGroup):
-
- """Declare light properties controllable in UI and translated to POV."""
-
- # former Space properties from removed Blender Internal
- use_limited_texture_context: BoolProperty(
- name="",
- description="Use the limited version of texture user (for ‘old shading’ mode)",
- default=True,
- )
-
- texture_context: EnumProperty(
- name="Texture context",
- description="Type of texture data to display and edit",
- items=(
- ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
- ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
- ('LAMP', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
- ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
- ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
- ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5), # "Show other data textures"
- ),
- default = 'MATERIAL',
- )
-
- shadow_method: EnumProperty(
- name="Shadow",
- description="",
- items=(("NOSHADOW", "No Shadow", "No Shadow"),
- ("RAY_SHADOW", "Ray Shadow", "Ray Shadow, Use ray tracing for shadow")),
- default="RAY_SHADOW",
- )
-
- active_texture_index: IntProperty(
- name = "Index for texture_slots",
- default = 0
- )
-
- use_halo: BoolProperty(
- name="Halo",
- description="Render spotlight with a volumetric halo",
- default=False,
- )
-
- halo_intensity: FloatProperty(
- name="Halo intensity",
- description="Brightness of the spotlight halo cone",
- soft_min=0.0, soft_max=1.0, default=1.0
- )
-
- shadow_ray_samples_x: IntProperty(
- name = "Number of samples taken extra (samples x samples)",
- min=1, soft_max=64,
- default = 1,
- )
-
- shadow_ray_samples_y: IntProperty(
- name = "Number of samples taken extra (samples x samples)",
- min=1, soft_max=64,
- default = 1,
- )
-
- shadow_ray_sample_method: EnumProperty(
- name="",
- description="Method for generating shadow samples: Adaptive QMC is fastest, Constant QMC is less noisy but slower",
- items=(
- ('ADAPTIVE_QMC', "", "Halton samples distribution", "",0),
- ('CONSTANT_QMC', "", "QMC samples distribution", "",1),
- ('CONSTANT_JITTERED', "", "Uses POV jitter keyword", "",2) # "Show other data textures"
- ),
- default = 'CONSTANT_JITTERED',
- )
-
- use_jitter: BoolProperty(
- name="Jitter",
- description="Use noise for sampling (Constant Jittered sampling)",
- default=False,
- )
-
-###############################################################################
-# World POV properties.
-###############################################################################
-class RenderPovSettingsWorld(PropertyGroup):
-
- """Declare world properties controllable in UI and translated to POV."""
-
- # former Space properties from removed Blender Internal
- use_limited_texture_context: BoolProperty(
- name="",
- description="Use the limited version of texture user (for ‘old shading’ mode)",
- default=True,
- )
-
- texture_context: EnumProperty(
- name="Texture context",
- description="Type of texture data to display and edit",
- items=(
- ('MATERIAL', "", "Show material textures", "MATERIAL",0), # "Show material textures"
- ('WORLD', "", "Show world textures", "WORLD",1), # "Show world textures"
- ('LIGHT', "", "Show lamp textures", "LIGHT",2), # "Show lamp textures"
- ('PARTICLES', "", "Show particles textures", "PARTICLES",3), # "Show particles textures"
- ('LINESTYLE', "", "Show linestyle textures", "LINE_DATA",4), # "Show linestyle textures"
- ('OTHER', "", "Show other data textures", "TEXTURE_DATA",5), # "Show other data textures"
- ),
- default = 'MATERIAL',
- )
-
- use_sky_blend: BoolProperty(
- name="Blend Sky",
- description="Render background with natural progression from horizon to zenith",
- default=False,
- )
-
- use_sky_paper: BoolProperty(
- name="Paper Sky",
- description="Flatten blend or texture coordinates",
- default=False,
- )
-
- use_sky_real: BoolProperty(
- name="Real Sky",
- description="Render background with a real horizon, relative to the camera angle",
- default=False,
- )
-
- horizon_color: FloatVectorProperty(
- name="Horizon Color",
- description="Color at the horizon",
- precision=4, step=0.01, min=0, soft_max=1,
- default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR',
- )
-
- zenith_color: FloatVectorProperty(
- name="Zenith Color",
- description="Color at the zenith",
- precision=4, step=0.01, min=0, soft_max=1,
- default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR',
- )
-
- ambient_color: FloatVectorProperty(
- name="Ambient Color",
- description="Ambient color of the world",
- precision=4, step=0.01, min=0, soft_max=1,
- default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR',
- )
- active_texture_index: IntProperty(
- name = "Index for texture_slots",
- default = 0,
- update = brush_texture_update
- )
-
-class WorldTextureSlot(PropertyGroup):
- """Declare world texture slot level properties for UI and translated to POV."""
-
- bl_idname="pov_texture_slots",
- bl_description="Texture_slots from Blender-2.79",
-
- # Adding a "real" texture datablock as property is not possible
- # (or at least not easy through a dynamically populated EnumProperty).
- # That's why we'll use a prop_search() UILayout function in ui.py.
- # So we'll assign the name of the needed texture datablock to the below StringProperty.
- texture : StringProperty(update=active_texture_name_from_uilist)
- # and use another temporary StringProperty to change the linked data
- texture_search : StringProperty(
- name="",
- update = active_texture_name_from_search,
- description = "Browse Texture to be linked",
- )
-
- blend_factor: FloatProperty(
- name="Blend",
- description="Amount texture affects color progression of the "
- "background",
- soft_min=0.0, soft_max=1.0, default=1.0
- )
-
- horizon_factor: FloatProperty(
- name="Horizon",
- description="Amount texture affects color of the horizon",
- soft_min=0.0, soft_max=1.0, default=1.0,
- )
-
- object: StringProperty(
- name="Object",
- description="Object to use for mapping with Object texture coordinates",
- default="",
- )
-
- offset: FloatVectorProperty(
- name="Offset",
- description=("Fine tune of the texture mapping X, Y and Z locations "),
- precision=4,
- step=0.1,
- soft_min= -100.0,
- soft_max=100.0,
- default=(0.0,0.0,0.0),
- options={'ANIMATABLE'},
- subtype='TRANSLATION',
- )
-
- scale: FloatVectorProperty(
- name="Size",
- subtype='XYZ',
- size=3,
- description="Set scaling for the texture’s X, Y and Z sizes ",
- precision=4,
- step=0.1,
- soft_min= -100.0,
- soft_max=100.0,
- default=(1.0,1.0,1.0),
- options={'ANIMATABLE'},
- )
-
- texture_coords: EnumProperty(
- name="Coordinates",
- description="Texture coordinates used to map the texture onto the background",
- items=(
- ("VIEW", "View", "Use view vector for the texture coordinates"),
- ("GLOBAL", "Global", "Use global coordinates for the texture coordinates (interior mist)"),
- ("ANGMAP", "AngMap", "Use 360 degree angular coordinates, e.g. for spherical light probes"),
- ("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
- ("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
- ("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
- ("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates")
- ),
- default="VIEW",
- )
-
- use_map_blend: BoolProperty(
- name="Blend Map",
- description="Affect the color progression of the background",
- default=True,
- )
-
- use_map_horizon: BoolProperty(
- name="Horizon Map",
- description="Affect the color of the horizon",
- default=False,
- )
-
- use_map_zenith_down: BoolProperty(
- name="",
- description="Affect the color of the zenith below",
- default=False,
- )
-
- use_map_zenith_up: BoolProperty(
- name="Zenith Up Map",
- description="Affect the color of the zenith above",
- default=False,
- )
-
- zenith_down_factor: FloatProperty(
- name="Zenith Down",
- description="Amount texture affects color of the zenith below",
- soft_min=0.0, soft_max=1.0, default=1.0
- )
-
- zenith_up_factor: FloatProperty(
- name="Zenith Up",
- description="Amount texture affects color of the zenith above",
- soft_min=0.0, soft_max=1.0, default=1.0
- )
-
-'''
-# class WORLD_TEXTURE_SLOTS_UL_layerlist(bpy.types.UIList):
-# texture_slots:
-
-class WorldTextureSlots(bpy.props.PropertyGroup):
- index = bpy.prop.PropertyInt(name='index')
- # foo = random prop
-
-bpy.types.World.texture_slots = bpy.props.CollectionProperty(type=PropertyGroup)
-
-for i in range(18): # length of world texture slots
- world.texture_slots.add()
-'''
-
-class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(bpy.types.UIList):
- # texture_slots:
- #index: bpy.props.IntProperty(name='index')
- # foo = random prop
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
- ob = data
- slot = item
- # ma = slot.name
- # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- # You should always start your row layout by a label (icon + text), or a non-embossed text field,
- # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
- # We use icon_value of label, as our given icon is an integer value, not an enum ID.
- # Note "data" names should never be translated!
- if slot:
- layout.prop(item, "texture", text="", emboss=False, icon='TEXTURE')
+class POV_OT_update_addon(bpy.types.Operator):
+ """Update this addon to the latest version."""
+
+ bl_idname = "pov.update_addon"
+ bl_label = "Update POV addon"
+
+ def execute(self, context):
+ import os, tempfile, shutil, urllib.request, urllib.error, zipfile
+
+ def recursive_overwrite(src, dest, ignore=None):
+ if os.path.isdir(src):
+ if not os.path.isdir(dest):
+ os.makedirs(dest)
+ files = os.listdir(src)
+ if ignore is not None:
+ ignored = ignore(src, files)
+ else:
+ ignored = set()
+ for f in files:
+ if f not in ignored:
+ recursive_overwrite(os.path.join(src, f), os.path.join(dest, f), ignore)
else:
- layout.label(text="New", translate=False, icon_value=icon)
- # 'GRID' layout type should be as compact as possible (typically a single icon!).
- elif self.layout_type in {'GRID'}:
- layout.alignment = 'CENTER'
- layout.label(text="", icon_value=icon)
-
-
-###############################################################################
-# Text POV properties.
-###############################################################################
-
-
-class RenderPovSettingsText(PropertyGroup):
+ shutil.copyfile(src, dest)
+
+ print('-' * 20)
+ print('Updating POV addon...')
+
+ with tempfile.TemporaryDirectory() as temp_dir_path:
+ temp_zip_path = os.path.join(temp_dir_path, 'master.zip')
+
+ # Download zip archive of latest addons master branch commit (So we also get presets)
+ # switch this URL back to the BF hosted one as soon as gitweb snapshot gets fixed
+ url = 'https://github.com/blender/blender-addons/archive/refs/heads/master.zip'
+ try:
+ print('Downloading', url)
+
+ with urllib.request.urlopen(url, timeout=60) as url_handle, open(
+ temp_zip_path, 'wb'
+ ) as file_handle:
+ file_handle.write(url_handle.read())
+ except urllib.error.URLError as err:
+ self.report({'ERROR'}, 'Could not download: %s' % err)
+
+ # Extract the zip
+ print('Extracting ZIP archive')
+ with zipfile.ZipFile(temp_zip_path) as zip:
+ for member in zip.namelist():
+ if 'blender-addons-master/render_povray' in member:
+ # Remove the first directory and the filename
+ # e.g. blender-addons-master/render_povray/shading_nodes.py
+ # becomes render_povray/shading_nodes.py
+ target_path = os.path.join(
+ temp_dir_path, os.path.join(*member.split('/')[1:-1])
+ )
+
+ filename = os.path.basename(member)
+ # Skip directories
+ if len(filename) == 0:
+ continue
+
+ # Create the target directory if necessary
+ if not os.path.exists(target_path):
+ os.makedirs(target_path)
+
+ source = zip.open(member)
+ target = open(os.path.join(target_path, filename), "wb")
+
+ with source, target:
+ shutil.copyfileobj(source, target)
+ print('copying', source, 'to', target)
+
+ extracted_render_povray_path = os.path.join(temp_dir_path, 'render_povray')
+
+ if not os.path.exists(extracted_render_povray_path):
+ self.report({'ERROR'}, 'Could not extract ZIP archive! Aborting.')
+ return {'FINISHED'}
+
+ # Find the old POV addon files
+ render_povray_dir = os.path.abspath(os.path.dirname(__file__))
+ print('POV addon addon folder:', render_povray_dir)
+
+ # TODO: Create backup
+
+ # Delete old POV addon files (only directories and *.py files, the user might have other stuff in there!)
+ print('Deleting old POV addon files')
+ # remove __init__.py
+ os.remove(os.path.join(render_povray_dir, '__init__.py'))
+ # remove all folders
+ DIRNAMES = 1
+ for dir in next(os.walk(render_povray_dir))[DIRNAMES]:
+ shutil.rmtree(os.path.join(render_povray_dir, dir))
+
+ print('Copying new POV addon files')
+ # copy new POV addon files
+ # copy __init__.py
+ shutil.copy2(
+ os.path.join(extracted_render_povray_path, '__init__.py'), render_povray_dir
+ )
+ # copy all folders
+ recursive_overwrite(extracted_render_povray_path, render_povray_dir)
- """Declare text properties to use UI as an IDE or render text snippets to POV."""
+ bpy.ops.preferences.addon_refresh()
+ print('POV addon update finished, restart Blender for the changes to take effect.')
+ print('-' * 20)
+ self.report({'WARNING'}, 'Restart Blender!')
+ return {'FINISHED'}
- custom_code: EnumProperty(
- name="Custom Code",
- description="rendered source: Both adds text at the "
- "top of the exported POV file",
- items=(
- ("3dview", "View", ""),
- ("text", "Text", ""),
- ("both", "Both", "")
- ),
- default="text",
- )
###############################################################################
# Povray Preferences.
###############################################################################
-class PovrayPreferences(AddonPreferences):
-
+class PovrayPreferences(bpy.types.AddonPreferences):
"""Declare preference variables to set up POV binary."""
bl_idname = __name__
@@ -5518,23 +342,19 @@ class PovrayPreferences(AddonPreferences):
name="Feature Set",
description="Choose between official (POV-Ray) or (UberPOV) "
"development branch features to write in the pov file",
- items= (
- ('povray', 'Official POV-Ray', '','PLUGIN', 0),
- ('uberpov', 'Unofficial UberPOV', '', 'PLUGIN', 1)
+ items=(
+ ("povray", "Official POV-Ray", "", "PLUGIN", 0),
+ ("uberpov", "Unofficial UberPOV", "", "PLUGIN", 1),
),
- default='povray',
+ default="povray",
)
filepath_povray: StringProperty(
- name="Binary Location",
- description="Path to renderer executable",
- subtype='FILE_PATH',
+ name="Binary Location", description="Path to renderer executable", subtype="FILE_PATH"
)
docpath_povray: StringProperty(
- name="Includes Location",
- description="Path to Insert Menu files",
- subtype='FILE_PATH',
+ name="Includes Location", description="Path to Insert Menu files", subtype="FILE_PATH"
)
use_sounds: BoolProperty(
@@ -5550,22 +370,21 @@ class PovrayPreferences(AddonPreferences):
filepath_complete_sound: StringProperty(
name="Finish Render Sound",
description="Path to finished render sound file",
- subtype='FILE_PATH',
+ subtype="FILE_PATH",
)
filepath_parse_error_sound: StringProperty(
name="Parse Error Sound",
description="Path to parsing time error sound file",
- subtype='FILE_PATH',
+ subtype="FILE_PATH",
)
filepath_cancel_sound: StringProperty(
name="Cancel Render Sound",
description="Path to cancelled or render time error sound file",
- subtype='FILE_PATH',
+ subtype="FILE_PATH",
)
- #shall we not move this to UI file?
def draw(self, context):
layout = self.layout
layout.prop(self, "branch_feature_set_povray")
@@ -5574,112 +393,50 @@ class PovrayPreferences(AddonPreferences):
layout.prop(self, "filepath_complete_sound")
layout.prop(self, "filepath_parse_error_sound")
layout.prop(self, "filepath_cancel_sound")
- layout.prop(self, "use_sounds", icon='SOUND')
+ layout.prop(self, "use_sounds", icon="SOUND")
+ layout.operator("pov.update_addon", icon='FILE_REFRESH')
-classes = (
- PovrayPreferences,
- RenderPovSettingsCamera,
- RenderPovSettingsLight,
- RenderPovSettingsWorld,
- MaterialTextureSlot,
- WorldTextureSlot,
- RenderPovSettingsMaterial,
- MaterialRaytraceTransparency,
- MaterialRaytraceMirror,
- MaterialSubsurfaceScattering,
- MaterialStrandSettings,
- RenderPovSettingsObject,
- RenderPovSettingsScene,
- RenderPovSettingsText,
- RenderPovSettingsTexture,
-)
+classes = (POV_OT_update_addon, PovrayPreferences)
def register():
-
- # bpy.utils.register_module(__name__) # DEPRECATED Now imported from bpy.utils import register_class
-
for cls in classes:
register_class(cls)
+ render_properties.register()
+ scenography_properties.register()
+ shading_properties.register()
+ texturing_properties.register()
+ object_properties.register()
+ scripting_properties.register()
+ scenography.register()
render.register()
- ui.register()
- primitives.register()
- nodes.register()
-
- '''
- bpy.types.VIEW3D_MT_add.prepend(ui.menu_func_add)
- bpy.types.TOPBAR_MT_file_import.append(ui.menu_func_import)
- bpy.types.TEXT_MT_templates.append(ui.menu_func_templates)
- bpy.types.RENDER_PT_POV_radiosity.prepend(ui.rad_panel_func)
- bpy.types.LIGHT_PT_POV_light.prepend(ui.light_panel_func)
- bpy.types.WORLD_PT_world.prepend(ui.world_panel_func)
- # was used for parametric objects but made the other addon unreachable on
- # unregister for other tools to use created a user action call instead
- # addon_utils.enable("add_mesh_extra_objects", default_set=False, persistent=True)
-
- # bpy.types.TEXTURE_PT_context_texture.prepend(TEXTURE_PT_povray_type)
- '''
- bpy.types.NODE_HT_header.append(ui.menu_func_nodes)
- nodeitems_utils.register_node_categories("POVRAYNODES", node_categories)
- bpy.types.Scene.pov = PointerProperty(type=RenderPovSettingsScene)
- # bpy.types.Modifier.pov = PointerProperty(type=RenderPovSettingsModifier)
- bpy.types.Material.pov_raytrace_transparency = PointerProperty(type=MaterialRaytraceTransparency)
- bpy.types.Material.pov = PointerProperty(type=RenderPovSettingsMaterial)
- bpy.types.Material.pov_subsurface_scattering = PointerProperty(type=MaterialSubsurfaceScattering)
- bpy.types.Material.strand = PointerProperty(type=MaterialStrandSettings)
- bpy.types.Material.pov_raytrace_mirror = PointerProperty(type=MaterialRaytraceMirror)
- bpy.types.Texture.pov = PointerProperty(type=RenderPovSettingsTexture)
- bpy.types.Object.pov = PointerProperty(type=RenderPovSettingsObject)
- bpy.types.Camera.pov = PointerProperty(type=RenderPovSettingsCamera)
- bpy.types.Light.pov = PointerProperty(type=RenderPovSettingsLight)
- bpy.types.World.pov = PointerProperty(type=RenderPovSettingsWorld)
- bpy.types.Material.pov_texture_slots = CollectionProperty(type=MaterialTextureSlot)
- bpy.types.World.pov_texture_slots = CollectionProperty(type=WorldTextureSlot)
- bpy.types.Text.pov = PointerProperty(type=RenderPovSettingsText)
+ base_ui.register()
+ scripting.register()
+ object_primitives.register()
def unregister():
- del bpy.types.Scene.pov
- del bpy.types.Material.pov
- del bpy.types.Material.pov_subsurface_scattering
- del bpy.types.Material.strand
- del bpy.types.Material.pov_raytrace_mirror
- del bpy.types.Material.pov_raytrace_transparency
- # del bpy.types.Modifier.pov
- del bpy.types.Texture.pov
- del bpy.types.Object.pov
- del bpy.types.Camera.pov
- del bpy.types.Light.pov
- del bpy.types.World.pov
- del bpy.types.World.pov_texture_slots
- del bpy.types.Material.pov_texture_slots
- del bpy.types.Text.pov
-
- nodeitems_utils.unregister_node_categories("POVRAYNODES")
- bpy.types.NODE_HT_header.remove(ui.menu_func_nodes)
- '''
- # bpy.types.TEXTURE_PT_context_texture.remove(TEXTURE_PT_povray_type)
- # addon_utils.disable("add_mesh_extra_objects", default_set=False)
- bpy.types.WORLD_PT_POV_world.remove(ui.world_panel_func)
- bpy.types.LIGHT_PT_POV_light.remove(ui.light_panel_func)
- bpy.types.RENDER_PT_POV_radiosity.remove(ui.rad_panel_func)
- bpy.types.TEXT_MT_templates.remove(ui.menu_func_templates)
- bpy.types.TOPBAR_MT_file_import.remove(ui.menu_func_import)
- bpy.types.VIEW3D_MT_add.remove(ui.menu_func_add)
- '''
- # bpy.utils.unregister_module(__name__)
-
- nodes.unregister()
- primitives.unregister()
- ui.unregister()
+ object_primitives.unregister()
+ scripting.unregister()
+ base_ui.unregister()
render.unregister()
+ scenography.unregister()
+ scripting_properties.unregister()
+ object_properties.unregister()
+ texturing_properties.unregister()
+ shading_properties.unregister()
+ scenography_properties.unregister()
+ render_properties.unregister()
for cls in reversed(classes):
unregister_class(cls)
-
if __name__ == "__main__":
register()
+
+# ------------8<---------[ BREAKPOINT ]--------------8<-----------# Move this snippet around
+# __import__('code').interact(local=dict(globals(), **locals())) # < and uncomment this line
+# ----------------------------------------------------------------# to inspect from Terminal
diff --git a/render_povray/base_ui.py b/render_povray/base_ui.py
new file mode 100755
index 00000000..85374ba3
--- /dev/null
+++ b/render_povray/base_ui.py
@@ -0,0 +1,307 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""User interface imports and preferences for the addon."""
+
+# import addon_utils
+# from time import sleep
+import bpy
+
+
+from bpy.app.handlers import persistent
+
+# from bpy.utils import register_class, unregister_class
+# from bpy.types import (
+# Operator,
+# Menu,
+# UIList,
+# Panel,
+# Brush,
+# Material,
+# Light,
+# World,
+# ParticleSettings,
+# FreestyleLineStyle,
+# )
+
+# from bl_operators.presets import AddPresetBase
+
+from . import (
+ render_gui,
+ scenography_gui,
+ object_gui,
+ shading_gui,
+ texturing_gui,
+ shading_nodes, # for POV specific nodes
+ scripting_gui,
+)
+
+
+############# POV-Centric WORKSPACE #############
+@persistent
+def povCentricWorkspace(dummy):
+ """Set up a POV centric Workspace if addon was activated and saved as default renderer.
+
+ This would bring a ’_RestrictData’ error because UI needs to be fully loaded before
+ workspace changes so registering this function in bpy.app.handlers is needed.
+ By default handlers are freed when loading new files, but here we want the handler
+ to stay running across multiple files as part of this add-on. That is why the
+ bpy.app.handlers.persistent decorator is used (@persistent) above.
+ """
+ # Scripting workspace may have been altered from factory though, so should
+ # we put all within a Try... Except AttributeErrors ? Any better solution ?
+ # Should it simply not run when opening existing file? be a preferences operator to create
+ # Moray like workspace
+ if 'Scripting' in bpy.data.workspaces:
+
+ wsp = bpy.data.workspaces.get('Scripting')
+ context = bpy.context
+ if context.scene.render.engine == 'POVRAY_RENDER' and wsp is not None:
+ bpy.ops.workspace.duplicate({'workspace': wsp})
+ bpy.data.workspaces['Scripting.001'].name = 'POV'
+ # Already done it would seem, but explicitly make this workspace the active one
+ context.window.workspace = bpy.data.workspaces['POV']
+ pov_screen = bpy.data.workspaces['POV'].screens[0]
+ pov_workspace = pov_screen.areas
+ pov_window = context.window
+ try:
+ # Already outliners but invert both types
+ pov_workspace[1].spaces[0].display_mode = 'LIBRARIES'
+ pov_workspace[3].spaces[0].display_mode = 'VIEW_LAYER'
+ except AttributeError:
+ # But not necessarily outliners in existing blend files
+ pass
+ override = bpy.context.copy()
+
+ for area in pov_workspace:
+ if area.type == 'VIEW_3D':
+ for region in [r for r in area.regions if r.type == 'WINDOW']:
+ for space in area.spaces:
+ if space.type == 'VIEW_3D':
+ # override['screen'] = pov_screen
+ override['area'] = area
+ override['region'] = region
+ # bpy.data.workspaces['POV'].screens[0].areas[6].spaces[0].width = 333 # Read only,
+ # how do we set ?
+ # This has a glitch:
+ # bpy.ops.screen.area_move(override, x=(area.x + area.width), y=(area.y + 5), delta=100)
+ # bpy.ops.screen.area_move(override, x=(area.x + 5), y=area.y, delta=-100)
+
+ bpy.ops.screen.space_type_set_or_cycle(
+ override, space_type='TEXT_EDITOR'
+ )
+ space.show_region_ui = True
+ # bpy.ops.screen.region_scale(override)
+ # bpy.ops.screen.region_scale()
+ break
+
+ elif area.type == 'CONSOLE':
+ for region in [r for r in area.regions if r.type == 'WINDOW']:
+ for space in area.spaces:
+ if space.type == 'CONSOLE':
+ override['screen'] = pov_screen
+ override['window'] = pov_window
+ override['area'] = area
+ override['region'] = region
+
+ area_x = area.x + (area.width / 2)
+ area_y = area.y + area.height
+ bpy.ops.screen.space_type_set_or_cycle(override, space_type='INFO')
+ try:
+ if area == pov_workspace[6] and bpy.ops.screen.area_move.poll(
+ override
+ ):
+ # bpy.ops.screen.area_move(override, x = area_x, y = area_y, delta = -300)
+ pass
+ # pov_window.cursor_warp(area_x, area_y-300) # Is manual move emulation necessary
+ # despite the delta?
+ except IndexError:
+ # Not necessarily so many areas in existing blend files
+ pass
+
+ break
+
+ elif area.type == 'INFO':
+ for region in [r for r in area.regions if r.type == 'WINDOW']:
+ for space in area.spaces:
+ if space.type == 'INFO':
+ # override['screen'] = pov_screen
+ override['area'] = area
+ override['region'] = region
+ bpy.ops.screen.space_type_set_or_cycle(
+ override, space_type='CONSOLE'
+ )
+
+ break
+
+ elif area.type == 'TEXT_EDITOR':
+ for region in [r for r in area.regions if r.type == 'WINDOW']:
+ for space in area.spaces:
+ if space.type == 'TEXT_EDITOR':
+ # override['screen'] = pov_screen
+ override['area'] = area
+ override['region'] = region
+ # bpy.ops.screen.space_type_set_or_cycle(space_type='VIEW_3D')
+ # space.type = 'VIEW_3D'
+ bpy.ops.screen.space_type_set_or_cycle(
+ override, space_type='VIEW_3D'
+ )
+
+ # bpy.ops.screen.area_join(override, cursor=(area.x, area.y + area.height))
+
+ break
+
+ if area.type == 'VIEW_3D':
+ for region in [r for r in area.regions if r.type == 'WINDOW']:
+ for space in area.spaces:
+ if space.type == 'VIEW_3D':
+ # override['screen'] = pov_screen
+ override['area'] = area
+ override['region'] = region
+ bpy.ops.screen.region_quadview(override)
+ space.region_3d.view_perspective = 'CAMERA'
+ # bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'TEXT_EDITOR')
+ # bpy.ops.screen.region_quadview(override)
+
+ elif area.type == 'OUTLINER':
+ for region in [
+ r for r in area.regions if r.type == 'HEADER' and (r.y - area.y)
+ ]:
+ for space in area.spaces:
+ if space.display_mode == 'LIBRARIES':
+ override['area'] = area
+ override['region'] = region
+ override['window'] = pov_window
+ bpy.ops.screen.region_flip(override)
+
+ bpy.data.workspaces.update()
+
+ '''
+ for window in bpy.context.window_manager.windows:
+ for area in [a for a in window.screen.areas if a.type == 'VIEW_3D']:
+ for region in [r for r in area.regions if r.type == 'WINDOW']:
+ context_override = {
+ 'window': window,
+ 'screen': window.screen,
+ 'area': area,
+ 'region': region,
+ 'space_data': area.spaces.active,
+ 'scene': bpy.context.scene
+ }
+ bpy.ops.view3d.camera_to_view(context_override)
+ '''
+
+ else:
+ print(
+ "\nPOV centric workspace available if you set render option\n"
+ "and save it in default file with CTRL+U"
+ )
+
+ else:
+ print(
+ "\nThe factory 'Scripting' workspace is needed before POV centric "
+ "\nworkspace may activate when POV is set as your default renderer"
+ )
+ ####################################UTF-8###################################
+ # Check and fix all strings in current .blend file to be valid UTF-8 Unicode
+ # sometimes needed for old, 2.4x / 2.6x area files
+ bpy.ops.wm.blend_strings_utf8_validate()
+
+
+def check_material(mat):
+ """Allow use of material properties buttons rather than nodes."""
+ if mat is not None:
+ if mat.use_nodes:
+ if not mat.node_tree: # FORMERLY : #mat.active_node_material is not None:
+ return True
+ return False
+ return True
+ return False
+
+
+def simple_material(mat):
+ """Test if a material uses nodes."""
+ if (mat is not None) and (not mat.use_nodes):
+ return True
+ return False
+
+
+def pov_context_tex_datablock(context):
+ """Recreate texture context type as deprecated in blender 2.8."""
+ idblock = context.brush
+ if idblock and context.scene.texture_context == 'OTHER':
+ return idblock
+
+ # idblock = bpy.context.active_object.active_material
+ idblock = context.view_layer.objects.active.active_material
+ if idblock and context.scene.texture_context == 'MATERIAL':
+ return idblock
+
+ idblock = context.scene.world
+ if idblock and context.scene.texture_context == 'WORLD':
+ return idblock
+
+ idblock = context.light
+ if idblock and context.scene.texture_context == 'LIGHT':
+ return idblock
+
+ if context.particle_system and context.scene.texture_context == 'PARTICLES':
+ idblock = context.particle_system.settings
+
+ return idblock
+
+ idblock = context.line_style
+ if idblock and context.scene.texture_context == 'LINESTYLE':
+ return idblock
+
+
+# class TextureTypePanel(TextureButtonsPanel):
+
+# @classmethod
+# def poll(cls, context):
+# tex = context.texture
+# engine = context.scene.render.engine
+# return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES))
+
+
+def register():
+ render_gui.register()
+ scenography_gui.register()
+ object_gui.register()
+ shading_gui.register()
+ texturing_gui.register()
+ shading_nodes.register()
+ scripting_gui.register()
+
+ if not povCentricWorkspace in bpy.app.handlers.load_post:
+ bpy.app.handlers.load_post.append(povCentricWorkspace)
+
+
+def unregister():
+ if povCentricWorkspace in bpy.app.handlers.load_post:
+ bpy.app.handlers.load_post.remove(povCentricWorkspace)
+
+ scripting_gui.unregister()
+ shading_nodes.unregister()
+ texturing_gui.unregister()
+ shading_gui.unregister()
+ object_gui.unregister()
+ scenography_gui.unregister()
+ render_gui.unregister()
diff --git a/render_povray/df3.py b/render_povray/df3_library.py
index b8434287..f802fb2d 100644..100755
--- a/render_povray/df3.py
+++ b/render_povray/df3_library.py
@@ -52,18 +52,19 @@ import sys
# -+-+-+- Start df3 Class -+-+-+-
+
class df3:
__version__ = '0.2'
__arraytype__ = 'f'
- __struct4byte__ = '>I'
- __struct2byte__ = '>H'
+ __struct4byte__ = '>I'
+ __struct2byte__ = '>H'
__struct2byte3__ = '>HHH'
- __struct1byte__ = '>B'
- __array4byte__ = 'I'
- __array2byte__ = 'H'
- __array1byte__ = 'B'
+ __struct1byte__ = '>B'
+ __array4byte__ = 'I'
+ __array2byte__ = 'H'
+ __array1byte__ = 'B'
def __init__(self, x=1, y=1, z=1):
self.maxX = x
@@ -73,7 +74,7 @@ class df3:
def clone(self, indf3):
self.voxel = array.array(self.__arraytype__)
- for i in range(indf3.sizeX()*indf3.sizeY()*indf3.sizeZ()):
+ for i in range(indf3.sizeX() * indf3.sizeY() * indf3.sizeZ()):
self.voxel[i] = indf3.voxel[i]
return self
@@ -98,35 +99,41 @@ class df3:
#### Voxel Access Functions
def get(self, x, y, z):
- return self.voxel[self.__voxa__(x,y,z)]
+ return self.voxel[self.__voxa__(x, y, z)]
def getB(self, x, y, z):
- if (x > self.sizeX() or x < 0): return 0
- if (y > self.sizeX() or y < 0): return 0
- if (z > self.sizeX() or z < 0): return 0
+ if x > self.sizeX() or x < 0:
+ return 0
+ if y > self.sizeX() or y < 0:
+ return 0
+ if z > self.sizeX() or z < 0:
+ return 0
- return self.voxel[self.__voxa__(x,y,z)]
+ return self.voxel[self.__voxa__(x, y, z)]
def set(self, x, y, z, val):
- self.voxel[self.__voxa__(x,y,z)] = val
+ self.voxel[self.__voxa__(x, y, z)] = val
def setB(self, x, y, z, val):
- if (x > self.sizeX() or x < 0): return
- if (y > self.sizeX() or y < 0): return
- if (z > self.sizeX() or z < 0): return
+ if x > self.sizeX() or x < 0:
+ return
+ if y > self.sizeX() or y < 0:
+ return
+ if z > self.sizeX() or z < 0:
+ return
- self.voxel[self.__voxa__(x,y,z)] = val
+ self.voxel[self.__voxa__(x, y, z)] = val
#### Scalar Functions
def mult(self, val):
- for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
+ for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
self.voxel[i] = self.voxel[i] * val
return self
def add(self, val):
- for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
+ for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
self.voxel[i] = self.voxel[i] + val
return self
@@ -134,8 +141,8 @@ class df3:
def max(self):
tmp = self.voxel[0]
- for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
- if (self.voxel[i] > tmp):
+ for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+ if self.voxel[i] > tmp:
tmp = self.voxel[i]
return tmp
@@ -143,8 +150,8 @@ class df3:
def min(self):
tmp = self.voxel[0]
- for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
- if (self.voxel[i] < tmp):
+ for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+ if self.voxel[i] < tmp:
tmp = self.voxel[i]
return tmp
@@ -152,30 +159,31 @@ class df3:
#### Vector Functions
def compare(self, indf3):
- if (self.__samesize__(indf3) == 0): return 0
+ if self.__samesize__(indf3) == 0:
+ return 0
- if (self.voxel == indf3.voxel):
+ if self.voxel == indf3.voxel:
return 1
return 0
def multV(self, indf3):
- if (self.__samesize__(indf3) == 0):
+ if self.__samesize__(indf3) == 0:
print("Cannot multiply voxels - not same size")
return
- for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
- self.voxel[i] = self.voxel[i]*indf3.voxel[i]
+ for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+ self.voxel[i] = self.voxel[i] * indf3.voxel[i]
return self
def addV(self, indf3):
- if (self.__samesize__(indf3) == 0):
+ if self.__samesize__(indf3) == 0:
print("Cannot add voxels - not same size")
return
- for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
- self.voxel[i] = self.voxel[i]+indf3.voxel[i]
+ for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+ self.voxel[i] = self.voxel[i] + indf3.voxel[i]
return self
@@ -183,31 +191,31 @@ class df3:
fx = filt.sizeX()
fy = filt.sizeY()
fz = filt.sizeZ()
- if (fx % 2 != 1):
+ if fx % 2 != 1:
print("Incompatible filter - must be odd number of X")
return self
- if (fy % 2 != 1):
+ if fy % 2 != 1:
print("Incompatible filter - must be odd number of Y")
return self
- if (fz % 2 != 1):
+ if fz % 2 != 1:
print("Incompatible filter - must be odd number of Z")
return self
- fdx = (fx-1)/2
- fdy = (fy-1)/2
- fdz = (fz-1)/2
- flen = fx*fy*fz
+ fdx = (fx - 1) / 2
+ fdy = (fy - 1) / 2
+ fdz = (fz - 1) / 2
+ flen = fx * fy * fz
- newV = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ());
+ newV = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ())
for x in range(self.sizeX()):
for y in range(self.sizeY()):
for z in range(self.sizeZ()):
- rip = self.__rip__(x-fdx, x+fdx, y-fdy, y+fdy, z-fdz, z+fdz)
+ rip = self.__rip__(x - fdx, x + fdx, y - fdy, y + fdy, z - fdz, z + fdz)
tmp = 0.0
for i in range(flen):
- tmp += rip[i]*filt.voxel[i]
- newV[self.__voxa__(x,y,z)] = tmp
+ tmp += rip[i] * filt.voxel[i]
+ newV[self.__voxa__(x, y, z)] = tmp
self.voxel = newV
@@ -221,64 +229,67 @@ class df3:
z = self.sizeZ()
try:
- f = open(file, 'wb');
+ f = open(file, 'wb')
except:
- print("Could not open " + file + " for write");
+ print("Could not open " + file + " for write")
return
- f.write(struct.pack(self.__struct2byte3__, x, y, z));
+ f.write(struct.pack(self.__struct2byte3__, x, y, z))
- tmp = self.__toInteger__(pow(2,depth)-1, rescale)
+ tmp = self.__toInteger__(pow(2, depth) - 1, rescale)
- if (depth > 16): # 32-bit
- for i in range( x*y*z ):
+ if depth > 16: # 32-bit
+ for i in range(x * y * z):
f.write(struct.pack(self.__struct4byte__, tmp[i]))
- elif (depth > 8): # 16-bit
- for i in range( x*y*z ):
+ elif depth > 8: # 16-bit
+ for i in range(x * y * z):
f.write(struct.pack(self.__struct2byte__, tmp[i]))
else:
- for i in range( x*y*z ):
+ for i in range(x * y * z):
f.write(struct.pack(self.__struct1byte__, tmp[i]))
def importDF3(self, file, scale=1):
try:
- f = open(file, 'rb');
+ f = open(file, 'rb')
size = os.stat(file)[stat.ST_SIZE]
except:
- print("Could not open " + file + " for read");
+ print("Could not open " + file + " for read")
return []
- (x, y, z) = struct.unpack(self.__struct2byte3__, f.read(6) )
+ (x, y, z) = struct.unpack(self.__struct2byte3__, f.read(6))
self.voxel = self.__create__(x, y, z)
self.maxX = x
self.maxY = y
self.maxZ = z
- size = size-6
- if (size == x*y*z): format = 8
- elif (size == 2*x*y*z): format = 16
- elif (size == 4*x*y*z): format = 32
-
- if (format == 32):
- for i in range(x*y*z):
- self.voxel[i] = float(struct.unpack(self.__struct4byte__, f.read(4) )[0])
- elif (format == 16):
- for i in range(x*y*z):
- self.voxel[i] = float(struct.unpack(self.__struct2byte__, f.read(2) )[0])
- elif (format == 8):
- for i in range(x*y*z):
- self.voxel[i] = float(struct.unpack(self.__struct1byte__, f.read(1) )[0])
+ size = size - 6
+ if size == x * y * z:
+ format = 8
+ elif size == 2 * x * y * z:
+ format = 16
+ elif size == 4 * x * y * z:
+ format = 32
+
+ if format == 32:
+ for i in range(x * y * z):
+ self.voxel[i] = float(struct.unpack(self.__struct4byte__, f.read(4))[0])
+ elif format == 16:
+ for i in range(x * y * z):
+ self.voxel[i] = float(struct.unpack(self.__struct2byte__, f.read(2))[0])
+ elif format == 8:
+ for i in range(x * y * z):
+ self.voxel[i] = float(struct.unpack(self.__struct1byte__, f.read(1))[0])
return self
#### Local classes not intended for user use
def __rip__(self, minX, maxX, minY, maxY, minZ, maxZ):
- sizeX = maxX-minX+1
- sizeY = maxY-minY+1
- sizeZ = maxZ-minZ+1
+ sizeX = maxX - minX + 1
+ sizeY = maxY - minY + 1
+ sizeZ = maxZ - minZ + 1
tmpV = self.__create__(sizeX, sizeY, sizeZ)
@@ -286,95 +297,99 @@ class df3:
for y in range(sizeY):
for z in range(sizeZ):
# Check X
- if ((minX + x) < 0):
- tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
- elif ((minX + x) > self.sizeX()-1):
- tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
+ if (minX + x) < 0:
+ tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
+ elif (minX + x) > self.sizeX() - 1:
+ tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
# Check Y
- elif ((minY + y) < 0):
- tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
- elif ((minY + y) > self.sizeY()-1):
- tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
+ elif (minY + y) < 0:
+ tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
+ elif (minY + y) > self.sizeY() - 1:
+ tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
# Check Z
- elif ((minZ + z) < 0):
- tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
- elif ((minZ + z) > self.sizeZ()-1):
- tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
+ elif (minZ + z) < 0:
+ tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
+ elif (minZ + z) > self.sizeZ() - 1:
+ tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
else:
- tmpV[(z*sizeZ+y)*sizeY+x] = self.get(minX+x,minY+y,minZ+z)
+ tmpV[(z * sizeZ + y) * sizeY + x] = self.get(minX + x, minY + y, minZ + z)
return tmpV
def __samesize__(self, indf3):
- if (self.sizeX() != indf3.sizeX()): return 0
- if (self.sizeY() != indf3.sizeY()): return 0
- if (self.sizeZ() != indf3.sizeZ()): return 0
+ if self.sizeX() != indf3.sizeX():
+ return 0
+ if self.sizeY() != indf3.sizeY():
+ return 0
+ if self.sizeZ() != indf3.sizeZ():
+ return 0
return 1
def __voxa__(self, x, y, z):
- return ((z*self.sizeY()+y)*self.sizeX()+x)
+ return (z * self.sizeY() + y) * self.sizeX() + x
def __create__(self, x, y, z, atype='0', init=1):
- if (atype == '0'):
+ if atype == '0':
tmp = self.__arraytype__
else:
tmp = atype
- if (init == 1):
- if tmp in ('f','d'):
- voxel = array.array(tmp, [0.0 for i in range(x*y*z)])
+ if init == 1:
+ if tmp in ('f', 'd'):
+ voxel = array.array(tmp, [0.0 for i in range(x * y * z)])
else:
- voxel = array.array(tmp, [0 for i in range(x*y*z)])
+ voxel = array.array(tmp, [0 for i in range(x * y * z)])
else:
voxel = array.array(tmp)
return voxel
def __toInteger__(self, scale, rescale=1):
- if (scale < pow(2,8)): # 8-bit
+ if scale < pow(2, 8): # 8-bit
tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array1byte__)
- elif (scale < pow(2,16)): # 16-bit
+ elif scale < pow(2, 16): # 16-bit
tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array2byte__)
- else: # 32-bit
+ else: # 32-bit
tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array4byte__)
maxVal = self.max()
print(scale)
- for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
- if (rescale == 1):
- tmp[i] = max(0,int(round(scale*self.voxel[i]/maxVal)))
+ for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
+ if rescale == 1:
+ tmp[i] = max(0, int(round(scale * self.voxel[i] / maxVal)))
else:
- tmp[i] = max(0,min(scale,int(round(self.voxel[i]))))
+ tmp[i] = max(0, min(scale, int(round(self.voxel[i]))))
return tmp
+
# -=-=-=- End df3 Class -=-=-=-
##########DEFAULT EXAMPLES
# if __name__ == '__main__':
- # localX = 80
- # localY = 90
- # localZ = 100
- ## Generate an output
- # temp = df3(localX, localY, localZ)
-
- # for i in range(localX):
- # for j in range(localY):
- # for k in range(localZ):
- # if (i >= (localX/2)):
- # temp.set(i, j, k, 1.0)
-
- # temp.exportDF3('temp.df3', 16)
+# localX = 80
+# localY = 90
+# localZ = 100
+## Generate an output
+# temp = df3(localX, localY, localZ)
+
+# for i in range(localX):
+# for j in range(localY):
+# for k in range(localZ):
+# if (i >= (localX/2)):
+# temp.set(i, j, k, 1.0)
+
+# temp.exportDF3('temp.df3', 16)
###############################################################################
- ## Import
- # temp2 = df3().importDF3('temp.df3')
- # temp2.mult(1/temp2.max())
+## Import
+# temp2 = df3().importDF3('temp.df3')
+# temp2.mult(1/temp2.max())
- ## Compare
- # print(temp2.size())
+## Compare
+# print(temp2.size())
- # if (temp.compare(temp2) == 0): print("DF3's Do Not Match")
+# if (temp.compare(temp2) == 0): print("DF3's Do Not Match")
###############################################################################
# ChangeLog
diff --git a/render_povray/nodes.py b/render_povray/nodes.py
deleted file mode 100644
index bbdb9754..00000000
--- a/render_povray/nodes.py
+++ /dev/null
@@ -1,1369 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-
-import bpy
-
-from bpy.utils import register_class
-from bpy.types import (
- Node,
- ShaderNodeTree,
- CompositorNodeTree,
- TextureNodeTree,
- #NodeSocket,
- Operator,
- )
-from bpy.props import (
- StringProperty,
- BoolProperty,
- IntProperty,
- FloatProperty,
- FloatVectorProperty,
- EnumProperty,
- #PointerProperty,
- #CollectionProperty,
- )
-
-
-
-############### object
-
-class ObjectNodeTree(bpy.types.NodeTree):
- '''Povray Material Nodes'''
-
- bl_idname = 'ObjectNodeTree'
- bl_label = 'Povray Object Nodes'
- bl_icon = 'PLUGIN'
-
- @classmethod
- def poll(cls, context):
- return context.scene.render.engine == 'POVRAY_RENDER'
-
- @classmethod
- def get_from_context(cls, context):
- ob = context.active_object
- if ob and ob.type not in {'LIGHT'}:
- ma = ob.active_material
- if ma is not None:
- nt_name = ma.node_tree
- if nt_name != '':
- return nt_name, ma, ma
- return (None, None, None)
-
- def update(self):
- self.refresh = True
-################### output #############################################################################################
-
-class PovrayOutputNode(Node, ObjectNodeTree):
- '''Output'''
- bl_idname = 'PovrayOutputNode'
- bl_label = 'Output'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- self.inputs.new('PovraySocketTexture', "Texture")
-
- def draw_buttons(self, context, layout):
-
- ob=context.object
- layout.prop(ob.pov, "object_ior",slider=True)
-
- def draw_buttons_ext(self, context, layout):
-
- ob=context.object
- layout.prop(ob.pov, "object_ior",slider=True)
-
- def draw_label(self):
- return "Output"
-
-
-
-################### material ###########################################################################################
-class PovrayTextureNode(Node, ObjectNodeTree):
- '''Texture'''
- bl_idname = 'PovrayTextureNode'
- bl_label = 'Simple texture'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- color=self.inputs.new('PovraySocketColor', "Pigment")
- color.default_value=(1,1,1)
- normal=self.inputs.new('NodeSocketFloat', "Normal")
- normal.hide_value=True
- finish=self.inputs.new('NodeSocketVector', "Finish")
- finish.hide_value=True
-
- self.outputs.new('PovraySocketTexture', "Texture")
-
- def draw_label(self):
- return "Simple texture"
-
-class PovrayFinishNode(Node, ObjectNodeTree):
- '''Finish'''
- bl_idname = 'PovrayFinishNode'
- bl_label = 'Finish'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- self.inputs.new('PovraySocketFloat_0_1', "Emission")
- ambient=self.inputs.new('NodeSocketVector', "Ambient")
- ambient.hide_value=True
- diffuse=self.inputs.new('NodeSocketVector', "Diffuse")
- diffuse.hide_value=True
- specular=self.inputs.new('NodeSocketVector', "Highlight")
- specular.hide_value=True
- mirror=self.inputs.new('NodeSocketVector', "Mirror")
- mirror.hide_value=True
- iridescence=self.inputs.new('NodeSocketVector', "Iridescence")
- iridescence.hide_value=True
- subsurface=self.inputs.new('NodeSocketVector', "Translucency")
- subsurface.hide_value=True
- self.outputs.new('NodeSocketVector', "Finish")
-
- def draw_label(self):
- return "Finish"
-
-class PovrayDiffuseNode(Node, ObjectNodeTree):
- '''Diffuse'''
- bl_idname = 'PovrayDiffuseNode'
- bl_label = 'Diffuse'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- intensity=self.inputs.new('PovraySocketFloat_0_1', "Intensity")
- intensity.default_value=0.8
- albedo=self.inputs.new('NodeSocketBool', "Albedo")
- albedo.default_value=False
- brilliance=self.inputs.new('PovraySocketFloat_0_10', "Brilliance")
- brilliance.default_value=1.8
- self.inputs.new('PovraySocketFloat_0_1', "Crand")
- self.outputs.new('NodeSocketVector', "Diffuse")
-
- def draw_label(self):
- return "Diffuse"
-
-class PovrayPhongNode(Node, ObjectNodeTree):
- '''Phong'''
- bl_idname = 'PovrayPhongNode'
- bl_label = 'Phong'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- albedo=self.inputs.new('NodeSocketBool', "Albedo")
- intensity=self.inputs.new('PovraySocketFloat_0_1', "Intensity")
- intensity.default_value=0.8
- phong_size=self.inputs.new('PovraySocketInt_0_256', "Size")
- phong_size.default_value=60
- metallic=self.inputs.new('PovraySocketFloat_0_1', "Metallic")
-
- self.outputs.new('NodeSocketVector', "Phong")
-
- def draw_label(self):
- return "Phong"
-
-class PovraySpecularNode(Node, ObjectNodeTree):
- '''Specular'''
- bl_idname = 'PovraySpecularNode'
- bl_label = 'Specular'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- albedo=self.inputs.new('NodeSocketBool', "Albedo")
- intensity=self.inputs.new('PovraySocketFloat_0_1', "Intensity")
- intensity.default_value=0.8
- roughness=self.inputs.new('PovraySocketFloat_0_1', "Roughness")
- roughness.default_value=0.02
- metallic=self.inputs.new('PovraySocketFloat_0_1', "Metallic")
-
- self.outputs.new('NodeSocketVector', "Specular")
-
- def draw_label(self):
- return "Specular"
-
-class PovrayMirrorNode(Node, ObjectNodeTree):
- '''Mirror'''
- bl_idname = 'PovrayMirrorNode'
- bl_label = 'Mirror'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- color=self.inputs.new('PovraySocketColor', "Color")
- color.default_value=(1,1,1)
- metallic=self.inputs.new('PovraySocketFloat_0_1', "Metallic")
- metallic.default_value=1.0
- exponent=self.inputs.new('PovraySocketFloat_0_1', "Exponent")
- exponent.default_value=1.0
- self.inputs.new('PovraySocketFloat_0_1', "Falloff")
- self.inputs.new('NodeSocketBool', "Fresnel")
- self.inputs.new('NodeSocketBool', "Conserve energy")
- self.outputs.new('NodeSocketVector', "Mirror")
-
- def draw_label(self):
- return "Mirror"
-
-class PovrayAmbientNode(Node, ObjectNodeTree):
- '''Ambient'''
- bl_idname = 'PovrayAmbientNode'
- bl_label = 'Ambient'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- self.inputs.new('PovraySocketColor', "Ambient")
-
- self.outputs.new('NodeSocketVector', "Ambient")
-
- def draw_label(self):
- return "Ambient"
-
-class PovrayIridescenceNode(Node, ObjectNodeTree):
- '''Iridescence'''
- bl_idname = 'PovrayIridescenceNode'
- bl_label = 'Iridescence'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- amount=self.inputs.new('NodeSocketFloat', "Amount")
- amount.default_value=0.25
- thickness=self.inputs.new('NodeSocketFloat', "Thickness")
- thickness.default_value=1
- self.inputs.new('NodeSocketFloat', "Turbulence")
-
- self.outputs.new('NodeSocketVector', "Iridescence")
-
- def draw_label(self):
- return "Iridescence"
-
-class PovraySubsurfaceNode(Node, ObjectNodeTree):
- '''Subsurface'''
- bl_idname = 'PovraySubsurfaceNode'
- bl_label = 'Subsurface'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- translucency=self.inputs.new('NodeSocketColor', "Translucency")
- translucency.default_value=(0,0,0,1)
- energy=self.inputs.new('PovraySocketInt_0_256', "Energy")
- energy.default_value=20
- self.outputs.new('NodeSocketVector', "Translucency")
-
- def draw_buttons(self, context, layout):
- scene=context.scene
- layout.prop(scene.pov, "sslt_enable",text="SSLT")
-
-
- def draw_buttons_ext(self, context, layout):
- scene=context.scene
- layout.prop(scene.pov, "sslt_enable",text="SSLT")
-
- def draw_label(self):
- return "Subsurface"
-
-#####################################################################################################
-
-class PovrayMappingNode(Node, ObjectNodeTree):
- '''Mapping'''
- bl_idname = 'PovrayMappingNode'
- bl_label = 'Mapping'
- bl_icon = 'SOUND'
-
- warp_type: EnumProperty(
- name="Warp Types",
- description="Select the type of warp",
- items=( ('cubic', "Cubic", ""), ('cylindrical', "Cylindrical", ""),('planar', "Planar", ""),
- ('spherical', "Spherical", ""),('toroidal', "Toroidal", ""),
- ('uv_mapping', "UV", ""),
- ('NONE', "None", "No indentation")),
- default='NONE')
-
- warp_orientation: EnumProperty(
- name="Warp Orientation",
- description="Select the orientation of warp",
- items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")),
- default='y')
-
- warp_dist_exp: FloatProperty(
- name="Distance exponent",
- description="Distance exponent",
- min=0.0, max=100.0, default=1.0)
-
- warp_tor_major_radius: FloatProperty(
- name="Major radius",
- description="Torus is distance from major radius",
- min=0.0, max=5.0, default=1.0)
-
- def init(self, context):
- self.outputs.new('NodeSocketVector', "Mapping")
-
- def draw_buttons(self, context, layout):
-
- column=layout.column()
- column.prop(self,"warp_type",text="Warp type")
- if self.warp_type in {'toroidal','spherical','cylindrical','planar'}:
- column.prop(self,"warp_orientation",text="Orientation")
- column.prop(self,"warp_dist_exp",text="Exponent")
- if self.warp_type=='toroidal':
- column.prop(self,"warp_tor_major_radius",text="Major R")
-
- def draw_buttons_ext(self, context, layout):
-
- column=layout.column()
- column.prop(self,"warp_type",text="Warp type")
- if self.warp_type in {'toroidal','spherical','cylindrical','planar'}:
- column.prop(self,"warp_orientation",text="Orientation")
- column.prop(self,"warp_dist_exp",text="Exponent")
- if self.warp_type=='toroidal':
- column.prop(self,"warp_tor_major_radius",text="Major R")
-
- def draw_label(self):
- return "Mapping"
-
-class PovrayMultiplyNode(Node, ObjectNodeTree):
- '''Multiply'''
- bl_idname = 'PovrayMultiplyNode'
- bl_label = 'Multiply'
- bl_icon = 'SOUND'
-
- amount_x : FloatProperty(
- name="X",
- description="Number of repeats",
- min=1.0, max=10000.0, default=1.0)
-
- amount_y : FloatProperty(
- name="Y",
- description="Number of repeats",
- min=1.0, max=10000.0, default=1.0)
-
- amount_z : FloatProperty(
- name="Z",
- description="Number of repeats",
- min=1.0, max=10000.0, default=1.0)
-
-
- def init(self, context):
- self.outputs.new('NodeSocketVector', "Amount")
-
- def draw_buttons(self, context, layout):
-
- column=layout.column()
- column.label(text="Amount")
- row=column.row(align=True)
- row.prop(self,"amount_x")
- row.prop(self,"amount_y")
- row.prop(self,"amount_z")
-
- def draw_buttons_ext(self, context, layout):
-
- column=layout.column()
- column.label(text="Amount")
- row=column.row(align=True)
- row.prop(self,"amount_x")
- row.prop(self,"amount_y")
- row.prop(self,"amount_z")
-
- def draw_label(self):
- return "Multiply"
-
-class PovrayTransformNode(Node, ObjectNodeTree):
- '''Transform'''
- bl_idname = 'PovrayTransformNode'
- bl_label = 'Transform'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- self.inputs.new('PovraySocketFloatUnlimited', "Translate x")
- self.inputs.new('PovraySocketFloatUnlimited', "Translate y")
- self.inputs.new('PovraySocketFloatUnlimited', "Translate z")
- self.inputs.new('PovraySocketFloatUnlimited', "Rotate x")
- self.inputs.new('PovraySocketFloatUnlimited', "Rotate y")
- self.inputs.new('PovraySocketFloatUnlimited', "Rotate z")
- sX = self.inputs.new('PovraySocketFloatUnlimited', "Scale x")
- sX.default_value = 1.0
- sY = self.inputs.new('PovraySocketFloatUnlimited', "Scale y")
- sY.default_value = 1.0
- sZ = self.inputs.new('PovraySocketFloatUnlimited', "Scale z")
- sZ.default_value = 1.0
-
- self.outputs.new('NodeSocketVector', "Transform")
-
- def draw_label(self):
- return "Transform"
-
-class PovrayValueNode(Node, ObjectNodeTree):
- '''Value'''
- bl_idname = 'PovrayValueNode'
- bl_label = 'Value'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- self.outputs.new('PovraySocketUniversal', "Value")
-
- def draw_label(self):
- return "Value"
-
-class PovrayModifierNode(Node, ObjectNodeTree):
- '''Modifier'''
- bl_idname = 'PovrayModifierNode'
- bl_label = 'Modifier'
- bl_icon = 'SOUND'
-
- def init(self, context):
-
- turb_x=self.inputs.new('PovraySocketFloat_0_10', "Turb X")
- turb_x.default_value=0.1
- turb_y=self.inputs.new('PovraySocketFloat_0_10', "Turb Y")
- turb_y.default_value=0.1
- turb_z=self.inputs.new('PovraySocketFloat_0_10', "Turb Z")
- turb_z.default_value=0.1
- octaves=self.inputs.new('PovraySocketInt_1_9', "Octaves")
- octaves.default_value=1
- lambat=self.inputs.new('PovraySocketFloat_0_10', "Lambda")
- lambat.default_value=2.0
- omega=self.inputs.new('PovraySocketFloat_0_10', "Omega")
- omega.default_value=0.5
- freq=self.inputs.new('PovraySocketFloat_0_10', "Frequency")
- freq.default_value=2.0
- self.inputs.new('PovraySocketFloat_0_10', "Phase")
-
- self.outputs.new('NodeSocketVector', "Modifier")
-
- def draw_label(self):
- return "Modifier"
-
-class PovrayPigmentNode(Node, ObjectNodeTree):
- '''Pigment'''
- bl_idname = 'PovrayPigmentNode'
- bl_label = 'Color'
-
- def init(self, context):
-
- color = self.inputs.new('PovraySocketColor', "Color")
- color.default_value = (1,1,1)
- povfilter = self.inputs.new('PovraySocketFloat_0_1', "Filter")
- transmit = self.inputs.new('PovraySocketFloat_0_1', "Transmit")
- self.outputs.new('NodeSocketColor', "Pigment")
-
- def draw_label(self):
- return "Color"
-
-class PovrayColorImageNode(Node, ObjectNodeTree):
- '''ColorImage'''
- bl_idname = 'PovrayColorImageNode'
- bl_label = 'Image map'
-
- map_type: bpy.props.EnumProperty(
- name="Map type",
- description="",
- items=( ('uv_mapping', "UV", ""),
- ('0', "Planar", "Default planar mapping"),
- ('1', "Spherical", "Spherical mapping"),
- ('2', "Cylindrical", "Cylindrical mapping"),
- ('5', "Torroidal", "Torus or donut shaped mapping")),
- default='0')
- image: StringProperty(maxlen=1024) # , subtype="FILE_PATH"
- interpolate: EnumProperty(
- name="Interpolate",
- description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
- items=(
- ('2', "Bilinear", "Gives bilinear interpolation"),
- ('4', "Normalized", "Gives normalized distance"),
- ),
- default='2')
- premultiplied: BoolProperty(default=False)
- once: BoolProperty(description="Not to repeat", default=False)
-
- def init(self, context):
-
- gamma=self.inputs.new('PovraySocketFloat_000001_10', "Gamma")
- gamma.default_value=2.0
- transmit=self.inputs.new('PovraySocketFloat_0_1', "Transmit")
- povfilter=self.inputs.new('PovraySocketFloat_0_1', "Filter")
- mapping=self.inputs.new('NodeSocketVector', "Mapping")
- mapping.hide_value=True
- transform=self.inputs.new('NodeSocketVector', "Transform")
- transform.hide_value=True
- modifier=self.inputs.new('NodeSocketVector', "Modifier")
- modifier.hide_value=True
-
- self.outputs.new('NodeSocketColor', "Pigment")
-
- def draw_buttons(self, context, layout):
-
- column=layout.column()
- im=None
- for image in bpy.data.images:
- if image.name == self.image:
- im=image
- split = column.split(factor=0.8,align=True)
- split.prop_search(self,"image",context.blend_data,"images",text="")
- split.operator("pov.imageopen",text="",icon="FILEBROWSER")
- if im is not None:
- column.prop(im,"source",text="")
- column.prop(self,"map_type",text="")
- column.prop(self,"interpolate",text="")
- row=column.row()
- row.prop(self,"premultiplied",text="Premul")
- row.prop(self,"once",text="Once")
-
- def draw_buttons_ext(self, context, layout):
-
- column=layout.column()
- im=None
- for image in bpy.data.images:
- if image.name == self.image:
- im=image
- split = column.split(factor=0.8,align=True)
- split.prop_search(self,"image",context.blend_data,"images",text="")
- split.operator("pov.imageopen",text="",icon="FILEBROWSER")
- if im is not None:
- column.prop(im,"source",text="")
- column.prop(self,"map_type",text="")
- column.prop(self,"interpolate",text="")
- row=column.row()
- row.prop(self,"premultiplied",text="Premul")
- row.prop(self,"once",text="Once")
-
- def draw_label(self):
- return "Image map"
-
-class PovrayBumpMapNode(Node, ObjectNodeTree):
- '''BumpMap'''
- bl_idname = 'PovrayBumpMapNode'
- bl_label = 'Bump map'
- bl_icon = 'SOUND'
-
- map_type : bpy.props.EnumProperty(
- name="Map type",
- description="",
- items=(
- ('uv_mapping', "UV", ""),
- ('0', "Planar", "Default planar mapping"),
- ('1', "Spherical", "Spherical mapping"),
- ('2', "Cylindrical", "Cylindrical mapping"),
- ('5', "Torroidal", "Torus or donut shaped mapping")
- ),
- default='0')
- image : StringProperty(maxlen=1024) # , subtype="FILE_PATH"
- interpolate : EnumProperty(
- name="Interpolate",
- description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
- items=(
- ('2', "Bilinear", "Gives bilinear interpolation"),
- ('4', "Normalized", "Gives normalized distance"),
- ),
- default='2')
- once : BoolProperty(description="Not to repeat", default=False)
-
- def init(self, context):
-
- self.inputs.new('PovraySocketFloat_0_10', "Normal")
- mapping=self.inputs.new('NodeSocketVector', "Mapping")
- mapping.hide_value=True
- transform=self.inputs.new('NodeSocketVector', "Transform")
- transform.hide_value=True
- modifier=self.inputs.new('NodeSocketVector', "Modifier")
- modifier.hide_value=True
-
- normal=self.outputs.new('NodeSocketFloat', "Normal")
- normal.hide_value=True
-
- def draw_buttons(self, context, layout):
-
- column=layout.column()
- im=None
- for image in bpy.data.images:
- if image.name == self.image:
- im=image
- split = column.split(percentage=0.8,align=True)
- split.prop_search(self,"image",context.blend_data,"images",text="")
- split.operator("pov.imageopen",text="",icon="FILEBROWSER")
- if im is not None:
- column.prop(im,"source",text="")
- column.prop(self,"map_type",text="")
- column.prop(self,"interpolate",text="")
- column.prop(self,"once",text="Once")
-
- def draw_buttons_ext(self, context, layout):
-
- column=layout.column()
- im=None
- for image in bpy.data.images:
- if image.name == self.image:
- im=image
- split = column.split(percentage=0.8,align=True)
- split.prop_search(self,"image",context.blend_data,"images",text="")
- split.operator("pov.imageopen",text="",icon="FILEBROWSER")
- if im is not None:
- column.prop(im,"source",text="")
- column.prop(self,"map_type",text="")
- column.prop(self,"interpolate",text="")
- column.prop(self,"once",text="Once")
-
- def draw_label(self):
- return "Bump Map"
-
-class PovrayImagePatternNode(Node, ObjectNodeTree):
- '''ImagePattern'''
- bl_idname = 'PovrayImagePatternNode'
- bl_label = 'Image pattern'
- bl_icon = 'SOUND'
-
- map_type: bpy.props.EnumProperty(
- name="Map type",
- description="",
- items=(
- ('uv_mapping', "UV", ""),
- ('0', "Planar", "Default planar mapping"),
- ('1', "Spherical", "Spherical mapping"),
- ('2', "Cylindrical", "Cylindrical mapping"),
- ('5', "Torroidal", "Torus or donut shaped mapping"),
- ),
- default='0')
- image: StringProperty(maxlen=1024) # , subtype="FILE_PATH"
- interpolate: EnumProperty(
- name="Interpolate",
- description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
- items=(
- ('2', "Bilinear", "Gives bilinear interpolation"),
- ('4', "Normalized", "Gives normalized distance"),
- ),
- default='2')
- premultiplied: BoolProperty(default=False)
- once: BoolProperty(description="Not to repeat", default=False)
- use_alpha: BoolProperty(default=True)
- def init(self, context):
-
- gamma=self.inputs.new('PovraySocketFloat_000001_10', "Gamma")
- gamma.default_value=2.0
-
- self.outputs.new('PovraySocketPattern', "Pattern")
-
- def draw_buttons(self, context, layout):
-
- column=layout.column()
- im=None
- for image in bpy.data.images:
- if image.name == self.image:
- im=image
- split = column.split(factor=0.8,align=True)
- split.prop_search(self,"image",context.blend_data,"images",text="")
- split.operator("pov.imageopen",text="",icon="FILEBROWSER")
- if im is not None:
- column.prop(im,"source",text="")
- column.prop(self,"map_type",text="")
- column.prop(self,"interpolate",text="")
- row=column.row()
- row.prop(self,"premultiplied",text="Premul")
- row.prop(self,"once",text="Once")
- column.prop(self,"use_alpha",text="Use alpha")
-
- def draw_buttons_ext(self, context, layout):
-
- column=layout.column()
- im=None
- for image in bpy.data.images:
- if image.name == self.image:
- im=image
- split = column.split(factor=0.8,align=True)
- split.prop_search(self,"image",context.blend_data,"images",text="")
- split.operator("pov.imageopen",text="",icon="FILEBROWSER")
- if im is not None:
- column.prop(im,"source",text="")
- column.prop(self,"map_type",text="")
- column.prop(self,"interpolate",text="")
- row=column.row()
- row.prop(self,"premultiplied",text="Premul")
- row.prop(self,"once",text="Once")
-
- def draw_label(self):
- return "Image pattern"
-
-class ShaderPatternNode(Node, ObjectNodeTree):
- '''Pattern'''
- bl_idname = 'ShaderPatternNode'
- bl_label = 'Other patterns'
-
- pattern : EnumProperty(
- name="Pattern",
- description="Agate, Crackle, Gradient, Pavement, Spiral, Tiling",
- items=(('agate', "Agate", ""),('crackle', "Crackle", ""),('gradient', "Gradient", ""),
- ('pavement', "Pavement", ""),
- ('spiral1', "Spiral 1", ""),
- ('spiral2', "Spiral 2", ""),
- ('tiling', "Tiling", "")),
- default='agate')
-
- agate_turb : FloatProperty(
- name="Agate turb",
- description="Agate turbulence",
- min=0.0, max=100.0, default=0.5)
-
- crackle_form_x : FloatProperty(
- name="X",
- description="Form vector X",
- min=-150.0, max=150.0, default=-1)
-
- crackle_form_y : FloatProperty(
- name="Y",
- description="Form vector Y",
- min=-150.0, max=150.0, default=1)
-
- crackle_form_z : FloatProperty(
- name="Z",
- description="Form vector Z",
- min=-150.0, max=150.0, default=0)
-
- crackle_metric : FloatProperty(
- name="Metric",
- description="Crackle metric",
- min=0.0, max=150.0, default=1)
-
- crackle_solid : BoolProperty(
- name="Solid",
- description="Crackle solid",
- default=False)
-
- spiral_arms : FloatProperty(
- name="Number",
- description="",
- min=0.0, max=256.0, default=2.0)
-
- tiling_number : IntProperty(
- name="Number",
- description="",
- min=1, max=27, default=1)
-
- gradient_orient : EnumProperty(
- name="Orient",
- description="",
- items=(('x', "X", ""),
- ('y', "Y", ""),
- ('z', "Z", "")),
- default='x')
-
- def init(self, context):
-
- pat = self.outputs.new('PovraySocketPattern', "Pattern")
-
- def draw_buttons(self, context, layout):
-
- layout.prop(self, "pattern",text="")
- if self.pattern=='agate':
- layout.prop(self, "agate_turb")
- if self.pattern=='crackle':
- layout.prop(self, "crackle_metric")
- layout.prop(self, "crackle_solid")
- layout.label(text="Form:")
- layout.prop(self, "crackle_form_x")
- layout.prop(self, "crackle_form_y")
- layout.prop(self, "crackle_form_z")
- if self.pattern in {"spiral1","spiral2"}:
- layout.prop(self, "spiral_arms")
- if self.pattern in {'tiling'}:
- layout.prop(self, "tiling_number")
- if self.pattern in {'gradient'}:
- layout.prop(self, "gradient_orient")
- def draw_buttons_ext(self, context, layout):
- pass
-
- def draw_label(self):
- return "Other patterns"
-
-class ShaderTextureMapNode(Node, ObjectNodeTree):
- '''Texture Map'''
- bl_idname = 'ShaderTextureMapNode'
- bl_label = 'Texture map'
-
- brick_size_x: FloatProperty(
- name="X",
- description="",
- min=0.0000, max=1.0000, default=0.2500)
-
- brick_size_y: FloatProperty(
- name="Y",
- description="",
- min=0.0000, max=1.0000, default=0.0525)
-
- brick_size_z: FloatProperty(
- name="Z",
- description="",
- min=0.0000, max=1.0000, default=0.1250)
-
- brick_mortar: FloatProperty(
- name="Mortar",
- description="Mortar",
- min=0.000, max=1.500, default=0.01)
-
- def init(self, context):
- mat = bpy.context.object.active_material
- self.inputs.new('PovraySocketPattern', "")
- color = self.inputs.new('NodeSocketColor', "Color ramp")
- color.hide_value = True
- for i in range(0,4):
- transform=self.inputs.new('PovraySocketTransform', "Transform")
- transform.hide_value=True
- number = mat.pov.inputs_number
- for i in range(number):
- self.inputs.new('PovraySocketTexture', "%s"%i)
-
-
- self.outputs.new('PovraySocketTexture', "Texture")
-
- def draw_buttons(self, context, layout):
-
- if self.inputs[0].default_value =='brick':
- layout.prop(self, "brick_mortar")
- layout.label(text="Brick size:")
- layout.prop(self, "brick_size_x")
- layout.prop(self, "brick_size_y")
- layout.prop(self, "brick_size_z")
-
- def draw_buttons_ext(self, context, layout):
-
- if self.inputs[0].default_value =='brick':
- layout.prop(self, "brick_mortar")
- layout.label(text="Brick size:")
- layout.prop(self, "brick_size_x")
- layout.prop(self, "brick_size_y")
- layout.prop(self, "brick_size_z")
-
- def draw_label(self):
- return "Texture map"
-
-
-class ShaderNormalMapNode(Node, ObjectNodeTree):
- '''Normal Map'''
- bl_idname = 'ShaderNormalMapNode'
- bl_label = 'Normal map'
-
- brick_size_x : FloatProperty(
- name="X",
- description="",
- min=0.0000, max=1.0000, default=0.2500)
-
- brick_size_y : FloatProperty(
- name="Y",
- description="",
- min=0.0000, max=1.0000, default=0.0525)
-
- brick_size_z : FloatProperty(
- name="Z",
- description="",
- min=0.0000, max=1.0000, default=0.1250)
-
- brick_mortar : FloatProperty(
- name="Mortar",
- description="Mortar",
- min=0.000, max=1.500, default=0.01)
-
- def init(self, context):
- self.inputs.new('PovraySocketPattern', "")
- normal = self.inputs.new('PovraySocketFloat_10', "Normal")
- slope = self.inputs.new('PovraySocketMap', "Slope map")
- for i in range(0,4):
- transform=self.inputs.new('PovraySocketTransform', "Transform")
- transform.hide_value=True
- self.outputs.new('PovraySocketNormal', "Normal")
-
- def draw_buttons(self, context, layout):
- #for i, inp in enumerate(self.inputs):
-
- if self.inputs[0].default_value =='brick':
- layout.prop(self, "brick_mortar")
- layout.label(text="Brick size:")
- layout.prop(self, "brick_size_x")
- layout.prop(self, "brick_size_y")
- layout.prop(self, "brick_size_z")
-
- def draw_buttons_ext(self, context, layout):
-
- if self.inputs[0].default_value =='brick':
- layout.prop(self, "brick_mortar")
- layout.label(text="Brick size:")
- layout.prop(self, "brick_size_x")
- layout.prop(self, "brick_size_y")
- layout.prop(self, "brick_size_z")
-
- def draw_label(self):
- return "Normal map"
-
-class ShaderNormalMapEntryNode(Node, ObjectNodeTree):
- '''Normal Map Entry'''
- bl_idname = 'ShaderNormalMapEntryNode'
- bl_label = 'Normal map entry'
-
- def init(self, context):
- self.inputs.new('PovraySocketFloat_0_1', "Stop")
- self.inputs.new('PovraySocketFloat_0_1', "Gray")
- def draw_label(self):
- return "Normal map entry"
-
-class IsoPropsNode(Node, CompositorNodeTree):
- '''ISO Props'''
- bl_idname = 'IsoPropsNode'
- bl_label = 'Iso'
- node_label : StringProperty(maxlen=1024)
- def init(self, context):
- ob = bpy.context.object
- self.node_label = ob.name
- textName = ob.pov.function_text
- if textName:
- text = bpy.data.texts[textName]
- for line in text.lines:
- split = line.body.split()
- if split[0] == "#declare":
- socket = self.inputs.new('NodeSocketFloat', "%s"%split[1])
- value = split[3].split(";")
- value = value[0]
- socket.default_value=float(value)
- def draw_label(self):
- return self.node_label
-
-class PovrayFogNode(Node, CompositorNodeTree):
- '''Fog settings'''
- bl_idname = 'PovrayFogNode'
- bl_label = 'Fog'
- def init(self, context):
- color=self.inputs.new('NodeSocketColor', "Color")
- color.default_value=(0.7,0.7,0.7,0.25)
- self.inputs.new('PovraySocketFloat_0_1', "Filter")
- distance = self.inputs.new('NodeSocketInt', "Distance")
- distance.default_value=150
- self.inputs.new('NodeSocketBool', "Ground")
- fog_offset=self.inputs.new('NodeSocketFloat', "Offset")
- fog_alt=self.inputs.new('NodeSocketFloat', "Altitude")
- turb = self.inputs.new('NodeSocketVector', "Turbulence")
- turb_depth=self.inputs.new('PovraySocketFloat_0_10', "Depth")
- turb_depth.default_value=0.5
- octaves=self.inputs.new('PovraySocketInt_1_9', "Octaves")
- octaves.default_value=5
- lambdat=self.inputs.new('PovraySocketFloat_0_10', "Lambda")
- lambdat.default_value=1.25
- omega=self.inputs.new('PovraySocketFloat_0_10', "Omega")
- omega.default_value=0.35
- translate = self.inputs.new('NodeSocketVector', "Translate")
- rotate = self.inputs.new('NodeSocketVector', "Rotate")
- scale = self.inputs.new('NodeSocketVector', "Scale")
- scale.default_value=(1,1,1)
- def draw_label(self):
- return "Fog"
-
-class PovraySlopeNode(Node, TextureNodeTree):
- '''Output'''
- bl_idname = 'PovraySlopeNode'
- bl_label = 'Slope Map'
-
- def init(self, context):
- self.use_custom_color = True
- self.color = (0,0.2,0)
- slope = self.inputs.new('PovraySocketSlope', "0")
- slope = self.inputs.new('PovraySocketSlope', "1")
- slopemap = self.outputs.new('PovraySocketMap', "Slope map")
- output.hide_value = True
- def draw_buttons(self, context, layout):
-
- layout.operator("pov.nodeinputadd")
- row = layout.row()
- row.label(text='Value')
- row.label(text='Height')
- row.label(text='Slope')
-
- def draw_buttons_ext(self, context, layout):
-
- layout.operator("pov.nodeinputadd")
- row = layout.row()
- row.label(text='Value')
- row.label(text='Height')
- row.label(text='Slope')
-
- def draw_label(self):
- return "Slope Map"
-
-######################################## Texture nodes ###############################
-class TextureOutputNode(Node, TextureNodeTree):
- '''Output'''
- bl_idname = 'TextureOutputNode'
- bl_label = 'Color Map'
-
- def init(self, context):
- tex = bpy.context.object.active_material.active_texture
- num_sockets = int(tex.pov.density_lines/32)
- for i in range(num_sockets):
- color = self.inputs.new('NodeSocketColor', "%s"%i)
- color.hide_value = True
-
- def draw_buttons(self, context, layout):
-
- layout.label(text="Color Ramps:")
-
- def draw_label(self):
- return "Color Map"
-
-
-##################################################################################
-#################################Operators########################################
-##################################################################################
-
-
-class NODE_OT_iso_add(Operator):
- bl_idname = "pov.nodeisoadd"
- bl_label = "Create iso props"
-
- def execute(self, context):
- ob = bpy.context.object
- if bpy.context.scene.use_nodes == False:
- bpy.context.scene.use_nodes = True
- tree = bpy.context.scene.node_tree
- for node in tree.nodes:
- if node.bl_idname == "IsoPropsNode" and node.label == ob.name:
- tree.nodes.remove(node)
- isonode = tree.nodes.new('IsoPropsNode')
- isonode.location = (0,0)
- isonode.label = ob.name
- return {'FINISHED'}
-
-class NODE_OT_map_create(Operator):
- bl_idname = "node.map_create"
- bl_label = "Create map"
-
- def execute(self, context):
- x = y = 0
- space = context.space_data
- tree = space.edit_tree
- for node in tree.nodes:
- if node.select == True:
- x,y = node.location
- node.select=False
- tmap = tree.nodes.new('ShaderTextureMapNode')
- tmap.location = (x - 200,y)
- return {'FINISHED'}
-
- def invoke(self, context, event):
- wm = context.window_manager
- return wm.invoke_props_dialog(self)
-
- def draw(self, context):
- layout = self.layout
- mat = context.object.active_material
- layout.prop(mat.pov,"inputs_number")
-
-class NODE_OT_povray_node_texture_map_add(Operator):
- bl_idname = "pov.nodetexmapadd"
- bl_label = "Texture map"
-
- def execute(self, context):
- tree=bpy.context.object.active_material.node_tree
- tmap = tree.nodes.active
- bpy.context.object.active_material.node_tree.nodes.active=tmap
- el=tmap.color_ramp.elements.new(0.5)
- for el in tmap.color_ramp.elements:
- el.color=(0,0,0,1)
- for inp in tmap.inputs:
- tmap.inputs.remove(inp)
- for outp in tmap.outputs:
- tmap.outputs.remove(outp)
- pattern=tmap.inputs.new('NodeSocketVector', "Pattern")
- pattern.hide_value=True
- for i in range(0,3):
- tmap.inputs.new('NodeSocketColor', "Shader")
- tmap.outputs.new('NodeSocketShader', "BSDF")
- tmap.label="Texture Map"
- return {'FINISHED'}
-
-
-class NODE_OT_povray_node_output_add(Operator):
- bl_idname = "pov.nodeoutputadd"
- bl_label = "Output"
-
- def execute(self, context):
- tree=bpy.context.object.active_material.node_tree
- tmap = tree.nodes.new('ShaderNodeOutputMaterial')
- bpy.context.object.active_material.node_tree.nodes.active=tmap
- for inp in tmap.inputs:
- tmap.inputs.remove(inp)
- tmap.inputs.new('NodeSocketShader', "Surface")
- tmap.label="Output"
- return {'FINISHED'}
-
-class NODE_OT_povray_node_layered_add(Operator):
- bl_idname = "pov.nodelayeredadd"
- bl_label = "Layered material"
-
- def execute(self, context):
- tree=bpy.context.object.active_material.node_tree
- tmap = tree.nodes.new('ShaderNodeAddShader')
- bpy.context.object.active_material.node_tree.nodes.active=tmap
- tmap.label="Layered material"
- return {'FINISHED'}
-
-class NODE_OT_povray_input_add(Operator):
- bl_idname = "pov.nodeinputadd"
- bl_label = "Add entry"
-
- def execute(self, context):
- node=bpy.context.object.active_material.node_tree.nodes.active
- if node.type in {'VALTORGB'}:
- number=1
- for inp in node.inputs:
- if inp.type=='SHADER':
- number+=1
- node.inputs.new('NodeSocketShader', "%s"%number)
- els=node.color_ramp.elements
- pos1=els[len(els)-1].position
- pos2=els[len(els)-2].position
- pos=(pos1-pos2)/2+pos2
- el=els.new(pos)
-
- if node.bl_idname == 'PovraySlopeNode':
- number=len(node.inputs)
- node.inputs.new('PovraySocketSlope', "%s"%number)
-
-
- return {'FINISHED'}
-
-class NODE_OT_povray_input_remove(Operator):
- bl_idname = "pov.nodeinputremove"
- bl_label = "Remove input"
-
- def execute(self, context):
- node=bpy.context.object.active_material.node_tree.nodes.active
- if node.type in {'VALTORGB','ADD_SHADER'}:
- number=len(node.inputs)-1
- if number > 5:
- inp=node.inputs[number]
- node.inputs.remove(inp)
- if node.type in {'VALTORGB'}:
- els=node.color_ramp.elements
- number=len(els)-2
- el=els[number]
- els.remove(el)
- return {'FINISHED'}
-
-class NODE_OT_povray_image_open(Operator):
- bl_idname = "pov.imageopen"
- bl_label = "Open"
-
- filepath: StringProperty(
- name="File Path",
- description="Open image",
- maxlen=1024,
- subtype='FILE_PATH',
- )
-
- def invoke(self, context, event):
- context.window_manager.fileselect_add(self)
- return {'RUNNING_MODAL'}
-
- def execute(self, context):
- im=bpy.data.images.load(self.filepath)
- node=context.object.active_material.node_tree.nodes.active
- node.image = im.name
- return {'FINISHED'}
-
-
-# class TEXTURE_OT_povray_open_image(Operator):
- # bl_idname = "pov.openimage"
- # bl_label = "Open Image"
-
- # filepath = StringProperty(
- # name="File Path",
- # description="Open image",
- # maxlen=1024,
- # subtype='FILE_PATH',
- # )
-
- # def invoke(self, context, event):
- # context.window_manager.fileselect_add(self)
- # return {'RUNNING_MODAL'}
-
- # def execute(self, context):
- # im=bpy.data.images.load(self.filepath)
- # tex = context.texture
- # tex.pov.image = im.name
- # view_layer = context.view_layer
- # view_layer.update()
- # return {'FINISHED'}
-
-class PovrayPatternNode(Operator):
- bl_idname = "pov.patternnode"
- bl_label = "Pattern"
-
- add=True
-
- def execute(self, context):
- space = context.space_data
- tree = space.edit_tree
- for node in tree.nodes:
- node.select=False
- if self.add==True:
- tmap = tree.nodes.new('ShaderNodeValToRGB')
- tmap.label="Pattern"
- for inp in tmap.inputs:
- tmap.inputs.remove(inp)
- for outp in tmap.outputs:
- tmap.outputs.remove(outp)
- pattern = tmap.inputs.new('PovraySocketPattern', "Pattern")
- pattern.hide_value = True
- mapping=tmap.inputs.new('NodeSocketVector', "Mapping")
- mapping.hide_value=True
- transform=tmap.inputs.new('NodeSocketVector', "Transform")
- transform.hide_value=True
- modifier=tmap.inputs.new('NodeSocketVector', "Modifier")
- modifier.hide_value=True
- for i in range(0,2):
- tmap.inputs.new('NodeSocketShader', "%s"%(i+1))
- tmap.outputs.new('NodeSocketShader', "Material")
- tmap.outputs.new('NodeSocketColor', "Color")
- tree.nodes.active=tmap
- self.add=False
- aNode=tree.nodes.active
- aNode.select=True
- v2d = context.region.view2d
- x, y = v2d.region_to_view(self.x, self.y)
- aNode.location = (x, y)
-
- def modal(self, context, event):
- if event.type == 'MOUSEMOVE':
- self.x = event.mouse_region_x
- self.y = event.mouse_region_y
- self.execute(context)
- return {'RUNNING_MODAL'}
- elif event.type == 'LEFTMOUSE':
- return {'FINISHED'}
- elif event.type in ('RIGHTMOUSE', 'ESC'):
- return {'CANCELLED'}
-
- return {'RUNNING_MODAL'}
-
- def invoke(self, context, event):
- context.window_manager.modal_handler_add(self)
- return {'RUNNING_MODAL'}
-
-class UpdatePreviewMaterial(Operator):
- '''Operator update preview material'''
- bl_idname = "node.updatepreview"
- bl_label = "Update preview"
-
- def execute(self, context):
- scene=context.view_layer
- ob=context.object
- for obj in scene.objects:
- if obj != ob:
- scene.objects.active = ob
- break
- scene.objects.active = ob
-
- def modal(self, context, event):
- if event.type == 'RIGHTMOUSE':
- self.execute(context)
- return {'FINISHED'}
- return {'PASS_THROUGH'}
-
- def invoke(self, context, event):
- context.window_manager.modal_handler_add(self)
- return {'RUNNING_MODAL'}
-
-class UpdatePreviewKey(Operator):
- '''Operator update preview keymap'''
- bl_idname = "wm.updatepreviewkey"
- bl_label = "Activate RMB"
- @classmethod
- def poll(cls, context):
- conf = context.window_manager.keyconfigs.active
- mapstr = "Node Editor"
- map = conf.keymaps[mapstr]
- try:
- map.keymap_items["node.updatepreview"]
- return False
- except:
- return True
-
- def execute(self, context):
- conf = context.window_manager.keyconfigs.active
- mapstr = "Node Editor"
- map = conf.keymaps[mapstr]
- map.keymap_items.new("node.updatepreview",type='RIGHTMOUSE',value="PRESS")
- return {'FINISHED'}
-
-classes = (
- ObjectNodeTree,
- PovrayOutputNode,
- PovrayTextureNode,
- PovrayFinishNode,
- PovrayDiffuseNode,
- PovrayPhongNode,
- PovraySpecularNode,
- PovrayMirrorNode,
- PovrayAmbientNode,
- PovrayIridescenceNode,
- PovraySubsurfaceNode,
- PovrayMappingNode,
- PovrayMultiplyNode,
- PovrayTransformNode,
- PovrayValueNode,
- PovrayModifierNode,
- PovrayPigmentNode,
- PovrayColorImageNode,
- PovrayBumpMapNode,
- PovrayImagePatternNode,
- ShaderPatternNode,
- ShaderTextureMapNode,
- ShaderNormalMapNode,
- ShaderNormalMapEntryNode,
- IsoPropsNode,
- PovrayFogNode,
- PovraySlopeNode,
- TextureOutputNode,
- NODE_OT_iso_add,
- NODE_OT_map_create,
- NODE_OT_povray_node_texture_map_add,
- NODE_OT_povray_node_output_add,
- NODE_OT_povray_node_layered_add,
- NODE_OT_povray_input_add,
- NODE_OT_povray_input_remove,
- NODE_OT_povray_image_open,
- PovrayPatternNode,
- UpdatePreviewMaterial,
- UpdatePreviewKey,
-)
-
-
-def register():
- #from bpy.utils import register_class
-
- for cls in classes:
- register_class(cls)
-
-
-def unregister():
- from bpy.utils import unregister_class
-
- for cls in classes:
- unregister_class(cls)
diff --git a/render_povray/object_curve_topology.py b/render_povray/object_curve_topology.py
new file mode 100755
index 00000000..5fa2b277
--- /dev/null
+++ b/render_povray/object_curve_topology.py
@@ -0,0 +1,974 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""Translate to POV the control point compounded geometries like polygon
+
+meshes or curve based shapes.
+"""
+
+import bpy
+
+from .shading import write_object_material
+
+################################ LOFT, ETC.
+def export_curves(ob, string_strip_hyphen, global_matrix, tab_write):
+ """write all curves based POV primitives to exported file """
+ name_orig = "OB" + ob.name
+ dataname_orig = "DATA" + ob.data.name
+
+ name = string_strip_hyphen(bpy.path.clean_name(name_orig))
+ dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
+
+ matrix = global_matrix @ ob.matrix_world
+ bezier_sweep = False
+ if ob.pov.curveshape == 'sphere_sweep':
+ # inlined spheresweep macro, which itself calls Shapes.inc:
+ file.write(' #include "shapes.inc"\n')
+
+ file.write(
+ ' #macro Shape_Bezierpoints_Sphere_Sweep(_merge_shape, _resolution, _points_array, _radius_array)\n'
+ )
+ file.write(' //input adjusting and inspection\n')
+ file.write(' #if(_resolution <= 1)\n')
+ file.write(' #local res = 1;\n')
+ file.write(' #else\n')
+ file.write(' #local res = int(_resolution);\n')
+ file.write(' #end\n')
+ file.write(' #if(dimensions(_points_array) != 1 | dimensions(_radius_array) != 1)\n')
+ file.write(' #error ""\n')
+ file.write(
+ ' #elseif(div(dimension_size(_points_array,1),4) - dimension_size(_points_array,1)/4 != 0)\n'
+ )
+ file.write(' #error ""\n')
+ file.write(
+ ' #elseif(dimension_size(_points_array,1) != dimension_size(_radius_array,1))\n'
+ )
+ file.write(' #error ""\n')
+ file.write(' #else\n')
+ file.write(' #local n_of_seg = div(dimension_size(_points_array,1), 4);\n')
+ file.write(' #local ctrl_pts_array = array[n_of_seg]\n')
+ file.write(' #local ctrl_rs_array = array[n_of_seg]\n')
+ file.write(' #for(i, 0, n_of_seg-1)\n')
+ file.write(
+ ' #local ctrl_pts_array[i] = array[4] {_points_array[4*i], _points_array[4*i+1], _points_array[4*i+2], _points_array[4*i+3]}\n'
+ )
+ file.write(
+ ' #local ctrl_rs_array[i] = array[4] {abs(_radius_array[4*i]), abs(_radius_array[4*i+1]), abs(_radius_array[4*i+2]), abs(_radius_array[4*i+3])}\n'
+ )
+ file.write(' #end\n')
+ file.write(' #end\n')
+
+ file.write(' //drawing\n')
+ file.write(' #local mockup1 =\n')
+ file.write(' #if(_merge_shape) merge{ #else union{ #end\n')
+ file.write(' #for(i, 0, n_of_seg-1)\n')
+ file.write(' #local has_head = true;\n')
+ file.write(' #if(i = 0)\n')
+ file.write(
+ ' #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[n_of_seg-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[n_of_seg-1][3] <= 0)\n'
+ )
+ file.write(' #local has_head = false;\n')
+ file.write(' #end\n')
+ file.write(' #else\n')
+ file.write(
+ ' #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[i-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[i-1][3] <= 0)\n'
+ )
+ file.write(' #local has_head = false;\n')
+ file.write(' #end\n')
+ file.write(' #end\n')
+ file.write(' #if(has_head = true)\n')
+ file.write(' sphere{\n')
+ file.write(' ctrl_pts_array[i][0], ctrl_rs_array[i][0]\n')
+ file.write(' }\n')
+ file.write(' #end\n')
+ file.write(' #local para_t = (1/2)/res;\n')
+ file.write(
+ ' #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
+ )
+ file.write(
+ ' #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
+ )
+ file.write(
+ ' #if(vlength(this_point-ctrl_pts_array[i][0]) > abs(this_radius-ctrl_rs_array[i][0]))\n'
+ )
+ file.write(' object{\n')
+ file.write(
+ ' Connect_Spheres(ctrl_pts_array[i][0], ctrl_rs_array[i][0], this_point, this_radius)\n'
+ )
+ file.write(' }\n')
+ file.write(' #end\n')
+ file.write(' sphere{\n')
+ file.write(' this_point, this_radius\n')
+ file.write(' }\n')
+ file.write(' #for(j, 1, res-1)\n')
+ file.write(' #local last_point = this_point;\n')
+ file.write(' #local last_radius = this_radius;\n')
+ file.write(' #local para_t = (1/2+j)/res;\n')
+ file.write(
+ ' #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
+ )
+ file.write(
+ ' #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
+ )
+ file.write(
+ ' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
+ )
+ file.write(' object{\n')
+ file.write(
+ ' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
+ )
+ file.write(' }\n')
+ file.write(' #end\n')
+ file.write(' sphere{\n')
+ file.write(' this_point, this_radius\n')
+ file.write(' }\n')
+ file.write(' #end\n')
+ file.write(' #local last_point = this_point;\n')
+ file.write(' #local last_radius = this_radius;\n')
+ file.write(' #local this_point = ctrl_pts_array[i][3];\n')
+ file.write(' #local this_radius = ctrl_rs_array[i][3];\n')
+ file.write(
+ ' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
+ )
+ file.write(' object{\n')
+ file.write(
+ ' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
+ )
+ file.write(' }\n')
+ file.write(' #end\n')
+ file.write(' sphere{\n')
+ file.write(' this_point, this_radius\n')
+ file.write(' }\n')
+ file.write(' #end\n')
+ file.write(' }\n')
+ file.write(' mockup1\n')
+ file.write(' #end\n')
+
+ for spl in ob.data.splines:
+ if spl.type == "BEZIER":
+ bezier_sweep = True
+ if ob.pov.curveshape in {'loft', 'birail'}:
+ n = 0
+ for spline in ob.data.splines:
+ n += 1
+ tab_write('#declare %s%s=spline {\n' % (dataname, n))
+ tab_write('cubic_spline\n')
+ lp = len(spline.points)
+ delta = 1 / (lp)
+ d = -delta
+ point = spline.points[lp - 1]
+ x, y, z, w = point.co[:]
+ tab_write('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
+ d += delta
+ for point in spline.points:
+ x, y, z, w = point.co[:]
+ tab_write('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
+ d += delta
+ for i in range(2):
+ point = spline.points[i]
+ x, y, z, w = point.co[:]
+ tab_write('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
+ d += delta
+ tab_write('}\n')
+ if ob.pov.curveshape in {'loft'}:
+ n = len(ob.data.splines)
+ tab_write('#declare %s = array[%s]{\n' % (dataname, (n + 3)))
+ tab_write('spline{%s%s},\n' % (dataname, n))
+ for i in range(n):
+ tab_write('spline{%s%s},\n' % (dataname, (i + 1)))
+ tab_write('spline{%s1},\n' % (dataname))
+ tab_write('spline{%s2}\n' % (dataname))
+ tab_write('}\n')
+ # Use some of the Meshmaker.inc macro, here inlined
+ file.write('#macro CheckFileName(FileName)\n')
+ file.write(' #local Len=strlen(FileName);\n')
+ file.write(' #if(Len>0)\n')
+ file.write(' #if(file_exists(FileName))\n')
+ file.write(' #if(Len>=4)\n')
+ file.write(' #local Ext=strlwr(substr(FileName,Len-3,4))\n')
+ file.write(
+ ' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
+ )
+ file.write(' #local Return=99;\n')
+ file.write(' #else\n')
+ file.write(' #local Return=0;\n')
+ file.write(' #end\n')
+ file.write(' #else\n')
+ file.write(' #local Return=0;\n')
+ file.write(' #end\n')
+ file.write(' #else\n')
+ file.write(' #if(Len>=4)\n')
+ file.write(' #local Ext=strlwr(substr(FileName,Len-3,4))\n')
+ file.write(
+ ' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
+ )
+ file.write(' #if (strcmp(Ext,".obj")=0)\n')
+ file.write(' #local Return=2;\n')
+ file.write(' #end\n')
+ file.write(' #if (strcmp(Ext,".pcm")=0)\n')
+ file.write(' #local Return=3;\n')
+ file.write(' #end\n')
+ file.write(' #if (strcmp(Ext,".arr")=0)\n')
+ file.write(' #local Return=4;\n')
+ file.write(' #end\n')
+ file.write(' #else\n')
+ file.write(' #local Return=1;\n')
+ file.write(' #end\n')
+ file.write(' #else\n')
+ file.write(' #local Return=1;\n')
+ file.write(' #end\n')
+ file.write(' #end\n')
+ file.write(' #else\n')
+ file.write(' #local Return=1;\n')
+ file.write(' #end\n')
+ file.write(' (Return)\n')
+ file.write('#end\n')
+
+ file.write('#macro BuildSpline(Arr, SplType)\n')
+ file.write(' #local Ds=dimension_size(Arr,1);\n')
+ file.write(' #local Asc=asc(strupr(SplType));\n')
+ file.write(' #if(Asc!=67 & Asc!=76 & Asc!=81) \n')
+ file.write(' #local Asc=76;\n')
+ file.write(
+ ' #debug "\nWrong spline type defined (C/c/L/l/N/n/Q/q), using default linear_spline\\n"\n'
+ )
+ file.write(' #end\n')
+ file.write(' spline {\n')
+ file.write(' #switch (Asc)\n')
+ file.write(' #case (67) //C cubic_spline\n')
+ file.write(' cubic_spline\n')
+ file.write(' #break\n')
+ file.write(' #case (76) //L linear_spline\n')
+ file.write(' linear_spline\n')
+ file.write(' #break\n')
+ file.write(' #case (78) //N linear_spline\n')
+ file.write(' natural_spline\n')
+ file.write(' #break\n')
+ file.write(' #case (81) //Q Quadratic_spline\n')
+ file.write(' quadratic_spline\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' #local Add=1/((Ds-2)-1);\n')
+ file.write(' #local J=0-Add;\n')
+ file.write(' #local I=0;\n')
+ file.write(' #while (I<Ds)\n')
+ file.write(' J\n')
+ file.write(' Arr[I]\n')
+ file.write(' #local I=I+1;\n')
+ file.write(' #local J=J+Add;\n')
+ file.write(' #end\n')
+ file.write(' }\n')
+ file.write('#end\n')
+
+ file.write('#macro BuildWriteMesh2(VecArr, NormArr, UVArr, U, V, FileName)\n')
+ # suppressed some file checking from original macro because no more separate files
+ file.write(' #local Write=0;\n')
+ file.write(' #debug concat("\\n\\n Building mesh2: \\n - vertex_vectors\\n")\n')
+ file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
+ file.write(' #switch (Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' " vertex_vectors {\\n",\n')
+ file.write(' " ", str(NumVertices,0,0),"\\n "\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' "# Vertices: ",str(NumVertices,0,0),"\\n"\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' str(2*NumVertices,0,0),",\\n"\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' "#declare VertexVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' mesh2 {\n')
+ file.write(' vertex_vectors {\n')
+ file.write(' NumVertices\n')
+ file.write(' #local I=0;\n')
+ file.write(' #while (I<NumVertices)\n')
+ file.write(' VecArr[I]\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(MeshFile, VecArr[I])\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(
+ ' "v ", VecArr[I].x," ", VecArr[I].y," ", VecArr[I].z,"\\n"\n'
+ )
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' VecArr[I].x,",", VecArr[I].y,",", VecArr[I].z,",\\n"\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(MeshFile, VecArr[I])\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' #local I=I+1;\n')
+ file.write(' #if(Write=1 | Write=4)\n')
+ file.write(' #if(mod(I,3)=0)\n')
+ file.write(' #write(MeshFile,"\\n ")\n')
+ file.write(' #end\n')
+ file.write(' #end \n')
+ file.write(' #end\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(MeshFile,"\\n }\\n")\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(MeshFile,"\\n")\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' // do nothing\n')
+ file.write(' #break\n')
+ file.write(' #case(4) \n')
+ file.write(' #write(MeshFile,"\\n}\\n")\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' }\n')
+
+ file.write(' #debug concat(" - normal_vectors\\n") \n')
+ file.write(' #local NumVertices=dimension_size(NormArr,1);\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' " normal_vectors {\\n",\n')
+ file.write(' " ", str(NumVertices,0,0),"\\n "\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' "# Normals: ",str(NumVertices,0,0),"\\n"\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' // do nothing\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(
+ ' "#declare NormalVectors= array[",str(NumVertices,0,0),"] {\\n "\n'
+ )
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' normal_vectors {\n')
+ file.write(' NumVertices\n')
+ file.write(' #local I=0;\n')
+ file.write(' #while (I<NumVertices)\n')
+ file.write(' NormArr[I]\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(MeshFile NormArr[I])\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(
+ ' "vn ", NormArr[I].x," ", NormArr[I].y," ", NormArr[I].z,"\\n"\n'
+ )
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' NormArr[I].x,",", NormArr[I].y,",", NormArr[I].z,",\\n"\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(MeshFile NormArr[I])\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' #local I=I+1;\n')
+ file.write(' #if(Write=1 | Write=4) \n')
+ file.write(' #if(mod(I,3)=0)\n')
+ file.write(' #write(MeshFile,"\\n ")\n')
+ file.write(' #end\n')
+ file.write(' #end\n')
+ file.write(' #end\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(MeshFile,"\\n }\\n")\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(MeshFile,"\\n")\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' //do nothing\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(MeshFile,"\\n}\\n")\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' }\n')
+
+ file.write(' #debug concat(" - uv_vectors\\n") \n')
+ file.write(' #local NumVertices=dimension_size(UVArr,1);\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile, \n')
+ file.write(' " uv_vectors {\\n",\n')
+ file.write(' " ", str(NumVertices,0,0),"\\n "\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' "# UV-vectors: ",str(NumVertices,0,0),"\\n"\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' // do nothing, *.pcm does not support uv-vectors\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' "#declare UVVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' uv_vectors {\n')
+ file.write(' NumVertices\n')
+ file.write(' #local I=0;\n')
+ file.write(' #while (I<NumVertices)\n')
+ file.write(' UVArr[I]\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(MeshFile UVArr[I])\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' "vt ", UVArr[I].u," ", UVArr[I].v,"\\n"\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' //do nothing\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(MeshFile UVArr[I])\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' #local I=I+1; \n')
+ file.write(' #if(Write=1 | Write=4)\n')
+ file.write(' #if(mod(I,3)=0)\n')
+ file.write(' #write(MeshFile,"\\n ")\n')
+ file.write(' #end \n')
+ file.write(' #end\n')
+ file.write(' #end \n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(MeshFile,"\\n }\\n")\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(MeshFile,"\\n")\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' //do nothing\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(MeshFile,"\\n}\\n")\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' }\n')
+ file.write('\n')
+ file.write(' #debug concat(" - face_indices\\n") \n')
+ file.write(' #declare NumFaces=U*V*2;\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' " face_indices {\\n"\n')
+ file.write(' " ", str(NumFaces,0,0),"\\n "\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write (\n')
+ file.write(' MeshFile,\n')
+ file.write(' "# faces: ",str(NumFaces,0,0),"\\n"\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' #write (\n')
+ file.write(' MeshFile,\n')
+ file.write(' "0,",str(NumFaces,0,0),",\\n"\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' "#declare FaceIndices= array[",str(NumFaces,0,0),"] {\\n "\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' face_indices {\n')
+ file.write(' NumFaces\n')
+ file.write(' #local I=0;\n')
+ file.write(' #local H=0;\n')
+ file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
+ file.write(' #while (I<V)\n')
+ file.write(' #local J=0;\n')
+ file.write(' #while (J<U)\n')
+ file.write(' #local Ind=(I*U)+I+J;\n')
+ file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(
+ ' "f ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+1+1,"/",Ind+1+1,"/",Ind+1+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n",\n'
+ )
+ file.write(
+ ' "f ",Ind+U+1+1,"/",Ind+U+1+1,"/",Ind+U+1+1," ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n"\n'
+ )
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(
+ ' Ind,",",Ind+NumVertices,",",Ind+1,",",Ind+1+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
+ )
+ file.write(
+ ' Ind+U+1,",",Ind+U+1+NumVertices,",",Ind,",",Ind+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
+ )
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(\n')
+ file.write(' MeshFile,\n')
+ file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
+ file.write(' )\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' #local J=J+1;\n')
+ file.write(' #local H=H+1;\n')
+ file.write(' #if(Write=1 | Write=4)\n')
+ file.write(' #if(mod(H,3)=0)\n')
+ file.write(' #write(MeshFile,"\\n ")\n')
+ file.write(' #end \n')
+ file.write(' #end\n')
+ file.write(' #end\n')
+ file.write(' #local I=I+1;\n')
+ file.write(' #end\n')
+ file.write(' }\n')
+ file.write(' #switch(Write)\n')
+ file.write(' #case(1)\n')
+ file.write(' #write(MeshFile, "\\n }\\n}")\n')
+ file.write(' #fclose MeshFile\n')
+ file.write(' #debug concat(" Done writing\\n")\n')
+ file.write(' #break\n')
+ file.write(' #case(2)\n')
+ file.write(' #fclose MeshFile\n')
+ file.write(' #debug concat(" Done writing\\n")\n')
+ file.write(' #break\n')
+ file.write(' #case(3)\n')
+ file.write(' #fclose MeshFile\n')
+ file.write(' #debug concat(" Done writing\\n")\n')
+ file.write(' #break\n')
+ file.write(' #case(4)\n')
+ file.write(' #write(MeshFile, "\\n}\\n}")\n')
+ file.write(' #fclose MeshFile\n')
+ file.write(' #debug concat(" Done writing\\n")\n')
+ file.write(' #break\n')
+ file.write(' #end\n')
+ file.write(' }\n')
+ file.write('#end\n')
+
+ file.write('#macro MSM(SplineArray, SplRes, Interp_type, InterpRes, FileName)\n')
+ file.write(' #declare Build=CheckFileName(FileName);\n')
+ file.write(' #if(Build=0)\n')
+ file.write(' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
+ file.write(' #include FileName\n')
+ file.write(' object{Surface}\n')
+ file.write(' #else\n')
+ file.write(' #local NumVertices=(SplRes+1)*(InterpRes+1);\n')
+ file.write(' #local NumFaces=SplRes*InterpRes*2;\n')
+ file.write(
+ ' #debug concat("\\n Calculating ",str(NumVertices,0,0)," vertices for ", str(NumFaces,0,0)," triangles\\n\\n")\n'
+ )
+ file.write(' #local VecArr=array[NumVertices]\n')
+ file.write(' #local NormArr=array[NumVertices]\n')
+ file.write(' #local UVArr=array[NumVertices]\n')
+ file.write(' #local N=dimension_size(SplineArray,1);\n')
+ file.write(' #local TempSplArr0=array[N];\n')
+ file.write(' #local TempSplArr1=array[N];\n')
+ file.write(' #local TempSplArr2=array[N];\n')
+ file.write(' #local PosStep=1/SplRes;\n')
+ file.write(' #local InterpStep=1/InterpRes;\n')
+ file.write(' #local Count=0;\n')
+ file.write(' #local Pos=0;\n')
+ file.write(' #while(Pos<=1)\n')
+ file.write(' #local I=0;\n')
+ file.write(' #if (Pos=0)\n')
+ file.write(' #while (I<N)\n')
+ file.write(' #local Spl=spline{SplineArray[I]}\n')
+ file.write(' #local TempSplArr0[I]=<0,0,0>+Spl(Pos);\n')
+ file.write(' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
+ file.write(' #local TempSplArr2[I]=<0,0,0>+Spl(Pos-PosStep);\n')
+ file.write(' #local I=I+1;\n')
+ file.write(' #end\n')
+ file.write(' #local S0=BuildSpline(TempSplArr0, Interp_type)\n')
+ file.write(' #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
+ file.write(' #local S2=BuildSpline(TempSplArr2, Interp_type)\n')
+ file.write(' #else\n')
+ file.write(' #while (I<N)\n')
+ file.write(' #local Spl=spline{SplineArray[I]}\n')
+ file.write(' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
+ file.write(' #local I=I+1;\n')
+ file.write(' #end\n')
+ file.write(' #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
+ file.write(' #end\n')
+ file.write(' #local J=0;\n')
+ file.write(' #while (J<=1)\n')
+ file.write(' #local P0=<0,0,0>+S0(J);\n')
+ file.write(' #local P1=<0,0,0>+S1(J);\n')
+ file.write(' #local P2=<0,0,0>+S2(J);\n')
+ file.write(' #local P3=<0,0,0>+S0(J+InterpStep);\n')
+ file.write(' #local P4=<0,0,0>+S0(J-InterpStep);\n')
+ file.write(' #local B1=P4-P0;\n')
+ file.write(' #local B2=P2-P0;\n')
+ file.write(' #local B3=P3-P0;\n')
+ file.write(' #local B4=P1-P0;\n')
+ file.write(' #local N1=vcross(B1,B2);\n')
+ file.write(' #local N2=vcross(B2,B3);\n')
+ file.write(' #local N3=vcross(B3,B4);\n')
+ file.write(' #local N4=vcross(B4,B1);\n')
+ file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
+ file.write(' #local VecArr[Count]=P0;\n')
+ file.write(' #local NormArr[Count]=Norm;\n')
+ file.write(' #local UVArr[Count]=<J,Pos>;\n')
+ file.write(' #local J=J+InterpStep;\n')
+ file.write(' #local Count=Count+1;\n')
+ file.write(' #end\n')
+ file.write(' #local S2=spline{S0}\n')
+ file.write(' #local S0=spline{S1}\n')
+ file.write(
+ ' #debug concat("\\r Done ", str(Count,0,0)," vertices : ", str(100*Count/NumVertices,0,2)," %")\n'
+ )
+ file.write(' #local Pos=Pos+PosStep;\n')
+ file.write(' #end\n')
+ file.write(' BuildWriteMesh2(VecArr, NormArr, UVArr, InterpRes, SplRes, "")\n')
+ file.write(' #end\n')
+ file.write('#end\n\n')
+
+ file.write('#macro Coons(Spl1, Spl2, Spl3, Spl4, Iter_U, Iter_V, FileName)\n')
+ file.write(' #declare Build=CheckFileName(FileName);\n')
+ file.write(' #if(Build=0)\n')
+ file.write(' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
+ file.write(' #include FileName\n')
+ file.write(' object{Surface}\n')
+ file.write(' #else\n')
+ file.write(' #local NumVertices=(Iter_U+1)*(Iter_V+1);\n')
+ file.write(' #local NumFaces=Iter_U*Iter_V*2;\n')
+ file.write(
+ ' #debug concat("\\n Calculating ", str(NumVertices,0,0), " vertices for ",str(NumFaces,0,0), " triangles\\n\\n")\n'
+ )
+ file.write(' #declare VecArr=array[NumVertices] \n')
+ file.write(' #declare NormArr=array[NumVertices] \n')
+ file.write(' #local UVArr=array[NumVertices] \n')
+ file.write(' #local Spl1_0=Spl1(0);\n')
+ file.write(' #local Spl2_0=Spl2(0);\n')
+ file.write(' #local Spl3_0=Spl3(0);\n')
+ file.write(' #local Spl4_0=Spl4(0);\n')
+ file.write(' #local UStep=1/Iter_U;\n')
+ file.write(' #local VStep=1/Iter_V;\n')
+ file.write(' #local Count=0;\n')
+ file.write(' #local I=0;\n')
+ file.write(' #while (I<=1)\n')
+ file.write(' #local Im=1-I;\n')
+ file.write(' #local J=0;\n')
+ file.write(' #while (J<=1)\n')
+ file.write(' #local Jm=1-J;\n')
+ file.write(
+ ' #local C0=Im*Jm*(Spl1_0)+Im*J*(Spl2_0)+I*J*(Spl3_0)+I*Jm*(Spl4_0);\n'
+ )
+ file.write(' #local P0=LInterpolate(I, Spl1(J), Spl3(Jm)) + \n')
+ file.write(' LInterpolate(Jm, Spl2(I), Spl4(Im))-C0;\n')
+ file.write(' #declare VecArr[Count]=P0;\n')
+ file.write(' #local UVArr[Count]=<J,I>;\n')
+ file.write(' #local J=J+UStep;\n')
+ file.write(' #local Count=Count+1;\n')
+ file.write(' #end\n')
+ file.write(' #debug concat(\n')
+ file.write(' "\r Done ", str(Count,0,0)," vertices : ",\n')
+ file.write(' str(100*Count/NumVertices,0,2)," %"\n')
+ file.write(' )\n')
+ file.write(' #local I=I+VStep;\n')
+ file.write(' #end\n')
+ file.write(' #debug "\r Normals "\n')
+ file.write(' #local Count=0;\n')
+ file.write(' #local I=0;\n')
+ file.write(' #while (I<=Iter_V)\n')
+ file.write(' #local J=0;\n')
+ file.write(' #while (J<=Iter_U)\n')
+ file.write(' #local Ind=(I*Iter_U)+I+J;\n')
+ file.write(' #local P0=VecArr[Ind];\n')
+ file.write(' #if(J=0)\n')
+ file.write(' #local P1=P0+(P0-VecArr[Ind+1]);\n')
+ file.write(' #else\n')
+ file.write(' #local P1=VecArr[Ind-1];\n')
+ file.write(' #end\n')
+ file.write(' #if (J=Iter_U)\n')
+ file.write(' #local P2=P0+(P0-VecArr[Ind-1]);\n')
+ file.write(' #else\n')
+ file.write(' #local P2=VecArr[Ind+1];\n')
+ file.write(' #end\n')
+ file.write(' #if (I=0)\n')
+ file.write(' #local P3=P0+(P0-VecArr[Ind+Iter_U+1]);\n')
+ file.write(' #else\n')
+ file.write(' #local P3=VecArr[Ind-Iter_U-1];\n')
+ file.write(' #end\n')
+ file.write(' #if (I=Iter_V)\n')
+ file.write(' #local P4=P0+(P0-VecArr[Ind-Iter_U-1]);\n')
+ file.write(' #else\n')
+ file.write(' #local P4=VecArr[Ind+Iter_U+1];\n')
+ file.write(' #end\n')
+ file.write(' #local B1=P4-P0;\n')
+ file.write(' #local B2=P2-P0;\n')
+ file.write(' #local B3=P3-P0;\n')
+ file.write(' #local B4=P1-P0;\n')
+ file.write(' #local N1=vcross(B1,B2);\n')
+ file.write(' #local N2=vcross(B2,B3);\n')
+ file.write(' #local N3=vcross(B3,B4);\n')
+ file.write(' #local N4=vcross(B4,B1);\n')
+ file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
+ file.write(' #declare NormArr[Count]=Norm;\n')
+ file.write(' #local J=J+1;\n')
+ file.write(' #local Count=Count+1;\n')
+ file.write(' #end\n')
+ file.write(
+ ' #debug concat("\r Done ", str(Count,0,0)," normals : ",str(100*Count/NumVertices,0,2), " %")\n'
+ )
+ file.write(' #local I=I+1;\n')
+ file.write(' #end\n')
+ file.write(' BuildWriteMesh2(VecArr, NormArr, UVArr, Iter_U, Iter_V, FileName)\n')
+ file.write(' #end\n')
+ file.write('#end\n\n')
+ # Empty curves
+ if len(ob.data.splines) == 0:
+ tab_write("\n//dummy sphere to represent empty curve location\n")
+ tab_write("#declare %s =\n" % dataname)
+ tab_write(
+ "sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
+ % (ob.location.x, ob.location.y, ob.location.z)
+ ) # ob.name > povdataname)
+ # And non empty curves
+ else:
+ if not bezier_sweep:
+ tab_write("#declare %s =\n" % dataname)
+ if ob.pov.curveshape == 'sphere_sweep' and not bezier_sweep:
+ tab_write("union {\n")
+ for spl in ob.data.splines:
+ if spl.type != "BEZIER":
+ spl_type = "linear"
+ if spl.type == "NURBS":
+ spl_type = "cubic"
+ points = spl.points
+ num_points = len(points)
+ if spl.use_cyclic_u:
+ num_points += 3
+
+ tab_write("sphere_sweep { %s_spline %s,\n" % (spl_type, num_points))
+ if spl.use_cyclic_u:
+ pt1 = points[len(points) - 1]
+ wpt1 = pt1.co
+ tab_write(
+ "<%.4g,%.4g,%.4g>,%.4g\n"
+ % (wpt1[0], wpt1[1], wpt1[2], pt1.radius * ob.data.bevel_depth)
+ )
+ for pt in points:
+ wpt = pt.co
+ tab_write(
+ "<%.4g,%.4g,%.4g>,%.4g\n"
+ % (wpt[0], wpt[1], wpt[2], pt.radius * ob.data.bevel_depth)
+ )
+ if spl.use_cyclic_u:
+ for i in range(0, 2):
+ end_pt = points[i]
+ wpt = end_pt.co
+ tab_write(
+ "<%.4g,%.4g,%.4g>,%.4g\n"
+ % (wpt[0], wpt[1], wpt[2], end_pt.radius * ob.data.bevel_depth)
+ )
+
+ tab_write("}\n")
+ # below not used yet?
+ if ob.pov.curveshape == 'sor':
+ for spl in ob.data.splines:
+ if spl.type in {'POLY', 'NURBS'}:
+ points = spl.points
+ num_points = len(points)
+ tab_write("sor { %s,\n" % num_points)
+ for pt in points:
+ wpt = pt.co
+ tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
+ else:
+ tab_write("box { 0,0\n")
+ if ob.pov.curveshape in {'lathe', 'prism'}:
+ spl = ob.data.splines[0]
+ if spl.type == "BEZIER":
+ points = spl.bezier_points
+ len_cur = len(points) - 1
+ len_pts = len_cur * 4
+ ifprism = ''
+ if ob.pov.curveshape in {'prism'}:
+ height = ob.data.extrude
+ ifprism = '-%s, %s,' % (height, height)
+ len_cur += 1
+ len_pts += 4
+ tab_write("%s { bezier_spline %s %s,\n" % (ob.pov.curveshape, ifprism, len_pts))
+ for i in range(0, len_cur):
+ p1 = points[i].co
+ pR = points[i].handle_right
+ end = i + 1
+ if i == len_cur - 1 and ob.pov.curveshape in {'prism'}:
+ end = 0
+ pL = points[end].handle_left
+ p2 = points[end].co
+ line = "<%.4g,%.4g>" % (p1[0], p1[1])
+ line += "<%.4g,%.4g>" % (pR[0], pR[1])
+ line += "<%.4g,%.4g>" % (pL[0], pL[1])
+ line += "<%.4g,%.4g>" % (p2[0], p2[1])
+ tab_write("%s\n" % line)
+ else:
+ points = spl.points
+ len_cur = len(points)
+ len_pts = len_cur
+ ifprism = ''
+ if ob.pov.curveshape in {'prism'}:
+ height = ob.data.extrude
+ ifprism = '-%s, %s,' % (height, height)
+ len_pts += 3
+ spl_type = 'quadratic'
+ if spl.type == 'POLY':
+ spl_type = 'linear'
+ tab_write(
+ "%s { %s_spline %s %s,\n" % (ob.pov.curveshape, spl_type, ifprism, len_pts)
+ )
+ if ob.pov.curveshape in {'prism'}:
+ pt = points[len(points) - 1]
+ wpt = pt.co
+ tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
+ for pt in points:
+ wpt = pt.co
+ tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
+ if ob.pov.curveshape in {'prism'}:
+ for i in range(2):
+ pt = points[i]
+ wpt = pt.co
+ tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
+ if bezier_sweep:
+ for p in range(len(ob.data.splines)):
+ br = []
+ depth = ob.data.bevel_depth
+ spl = ob.data.splines[p]
+ points = spl.bezier_points
+ len_cur = len(points) - 1
+ num_points = len_cur * 4
+ if spl.use_cyclic_u:
+ len_cur += 1
+ num_points += 4
+ tab_write("#declare %s_points_%s = array[%s]{\n" % (dataname, p, num_points))
+ for i in range(len_cur):
+ p1 = points[i].co
+ pR = points[i].handle_right
+ end = i + 1
+ if spl.use_cyclic_u and i == (len_cur - 1):
+ end = 0
+ pL = points[end].handle_left
+ p2 = points[end].co
+ r3 = points[end].radius * depth
+ r0 = points[i].radius * depth
+ r1 = 2 / 3 * r0 + 1 / 3 * r3
+ r2 = 1 / 3 * r0 + 2 / 3 * r3
+ br.append((r0, r1, r2, r3))
+ line = "<%.4g,%.4g,%.4f>" % (p1[0], p1[1], p1[2])
+ line += "<%.4g,%.4g,%.4f>" % (pR[0], pR[1], pR[2])
+ line += "<%.4g,%.4g,%.4f>" % (pL[0], pL[1], pL[2])
+ line += "<%.4g,%.4g,%.4f>" % (p2[0], p2[1], p2[2])
+ tab_write("%s\n" % line)
+ tab_write("}\n")
+ tab_write("#declare %s_radii_%s = array[%s]{\n" % (dataname, p, len(br) * 4))
+ for rad_tuple in br:
+ tab_write(
+ '%.4f,%.4f,%.4f,%.4f\n'
+ % (rad_tuple[0], rad_tuple[1], rad_tuple[2], rad_tuple[3])
+ )
+ tab_write("}\n")
+ if len(ob.data.splines) == 1:
+ tab_write('#declare %s = object{\n' % dataname)
+ tab_write(
+ ' Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s) \n'
+ % (ob.data.resolution_u, dataname, p, dataname, p)
+ )
+ else:
+ tab_write('#declare %s = union{\n' % dataname)
+ for p in range(len(ob.data.splines)):
+ tab_write(
+ ' object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s)} \n'
+ % (ob.data.resolution_u, dataname, p, dataname, p)
+ )
+ # tab_write('#include "bezier_spheresweep.inc"\n') #now inlined
+ # tab_write('#declare %s = object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_bezier_points, %.4f) \n'%(dataname,ob.data.resolution_u,dataname,ob.data.bevel_depth))
+ if ob.pov.curveshape in {'loft'}:
+ tab_write('object {MSM(%s,%s,"c",%s,"")\n' % (dataname, ob.pov.res_u, ob.pov.res_v))
+ if ob.pov.curveshape in {'birail'}:
+ splines = '%s1,%s2,%s3,%s4' % (dataname, dataname, dataname, dataname)
+ tab_write('object {Coons(%s, %s, %s, "")\n' % (splines, ob.pov.res_u, ob.pov.res_v))
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(ob.data)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ if ob.pov.curveshape in {'prism'}:
+ tab_write("rotate <90,0,0>\n")
+ tab_write("scale y*-1\n")
+ tab_write("}\n")
diff --git a/render_povray/object_gui.py b/render_povray/object_gui.py
new file mode 100755
index 00000000..9fbf8a8b
--- /dev/null
+++ b/render_povray/object_gui.py
@@ -0,0 +1,728 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""User interface for the POV tools"""
+
+import bpy
+
+from bpy.utils import register_class, unregister_class
+from bpy.types import (
+ # Operator,
+ Menu,
+ Panel,
+)
+
+
+# Example of wrapping every class 'as is'
+from bl_ui import properties_data_modifier
+
+for member in dir(properties_data_modifier):
+ subclass = getattr(properties_data_modifier, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_data_modifier
+
+
+from bl_ui import properties_data_mesh
+
+# These panels are kept
+properties_data_mesh.DATA_PT_custom_props_mesh.COMPAT_ENGINES.add('POVRAY_RENDER')
+properties_data_mesh.DATA_PT_context_mesh.COMPAT_ENGINES.add('POVRAY_RENDER')
+
+## make some native panels contextual to some object variable
+## by recreating custom panels inheriting their properties
+
+
+from .scripting_gui import VIEW_MT_POV_import
+
+
+class ModifierButtonsPanel:
+ """Use this class to define buttons from the modifier tab of
+ properties window."""
+
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "modifier"
+ # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
+
+ @classmethod
+ def poll(cls, context):
+ mods = context.object.modifiers
+ rd = context.scene.render
+ return mods and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class ObjectButtonsPanel:
+ """Use this class to define buttons from the object tab of
+ properties window."""
+
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "object"
+ # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
+
+ @classmethod
+ def poll(cls, context):
+ obj = context.object
+ rd = context.scene.render
+ return obj and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class PovDataButtonsPanel(properties_data_mesh.MeshButtonsPanel):
+ """Use this class to define buttons from the edit data tab of
+ properties window."""
+
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ POV_OBJECT_TYPES = {
+ 'PLANE',
+ 'BOX',
+ 'SPHERE',
+ 'CYLINDER',
+ 'CONE',
+ 'TORUS',
+ 'BLOB',
+ 'ISOSURFACE',
+ 'SUPERELLIPSOID',
+ 'SUPERTORUS',
+ 'HEIGHT_FIELD',
+ 'PARAMETRIC',
+ 'POLYCIRCLE',
+ }
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ obj = context.object
+ # We use our parent class poll func too, avoids to re-define too much things...
+ return (
+ super(PovDataButtonsPanel, cls).poll(context)
+ and obj
+ and obj.pov.object_as not in cls.POV_OBJECT_TYPES
+ )
+
+
+# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
+# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
+# So we simply have to explicitly copy here the interesting bits. ;)
+class DATA_PT_POV_normals(PovDataButtonsPanel, Panel):
+ bl_label = properties_data_mesh.DATA_PT_normals.bl_label
+
+ draw = properties_data_mesh.DATA_PT_normals.draw
+
+
+class DATA_PT_POV_texture_space(PovDataButtonsPanel, Panel):
+ bl_label = properties_data_mesh.DATA_PT_texture_space.bl_label
+ bl_options = properties_data_mesh.DATA_PT_texture_space.bl_options
+
+ draw = properties_data_mesh.DATA_PT_texture_space.draw
+
+
+class DATA_PT_POV_vertex_groups(PovDataButtonsPanel, Panel):
+ bl_label = properties_data_mesh.DATA_PT_vertex_groups.bl_label
+
+ draw = properties_data_mesh.DATA_PT_vertex_groups.draw
+
+
+class DATA_PT_POV_shape_keys(PovDataButtonsPanel, Panel):
+ bl_label = properties_data_mesh.DATA_PT_shape_keys.bl_label
+
+ draw = properties_data_mesh.DATA_PT_shape_keys.draw
+
+
+class DATA_PT_POV_uv_texture(PovDataButtonsPanel, Panel):
+ bl_label = properties_data_mesh.DATA_PT_uv_texture.bl_label
+
+ draw = properties_data_mesh.DATA_PT_uv_texture.draw
+
+
+class DATA_PT_POV_vertex_colors(PovDataButtonsPanel, Panel):
+ bl_label = properties_data_mesh.DATA_PT_vertex_colors.bl_label
+
+ draw = properties_data_mesh.DATA_PT_vertex_colors.draw
+
+
+class DATA_PT_POV_customdata(PovDataButtonsPanel, Panel):
+ bl_label = properties_data_mesh.DATA_PT_customdata.bl_label
+ bl_options = properties_data_mesh.DATA_PT_customdata.bl_options
+ draw = properties_data_mesh.DATA_PT_customdata.draw
+
+
+del properties_data_mesh
+
+
+class MODIFIERS_PT_POV_modifiers(ModifierButtonsPanel, Panel):
+ """Use this class to define pov modifier buttons. (For booleans)"""
+
+ bl_label = "POV-Ray"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ # def draw_header(self, context):
+ # scene = context.scene
+ # self.layout.prop(scene.pov, "boolean_mod", text="")
+
+ def draw(self, context):
+ # scene = context.scene
+ layout = self.layout
+ ob = context.object
+ mod = ob.modifiers
+ col = layout.column()
+ # Find Boolean Modifiers for displaying CSG option
+ onceCSG = 0
+ for mod in ob.modifiers:
+ if onceCSG == 0:
+ if mod:
+ if mod.type == 'BOOLEAN':
+ col.prop(ob.pov, "boolean_mod")
+ onceCSG = 1
+
+ if ob.pov.boolean_mod == "POV":
+ split = layout.split()
+ col = layout.column()
+ # Inside Vector for CSG
+ col.prop(ob.pov, "inside_vector")
+
+
+class OBJECT_PT_POV_obj_parameters(ObjectButtonsPanel, Panel):
+ """Use this class to define pov specific object level options buttons."""
+
+ bl_label = "POV"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+
+ engine = context.scene.render.engine
+ return engine in cls.COMPAT_ENGINES
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ split = layout.split()
+
+ col = split.column(align=True)
+
+ col.label(text="Radiosity:")
+ col.prop(obj.pov, "importance_value", text="Importance")
+ col.label(text="Photons:")
+ col.prop(obj.pov, "collect_photons", text="Receive Photon Caustics")
+ if obj.pov.collect_photons:
+ col.prop(obj.pov, "spacing_multiplier", text="Photons Spacing Multiplier")
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(obj.pov, "hollow")
+ col.prop(obj.pov, "double_illuminate")
+
+ if obj.type == 'META' or obj.pov.curveshape == 'lathe':
+ # if obj.pov.curveshape == 'sor'
+ col.prop(obj.pov, "sturm")
+ col.prop(obj.pov, "no_shadow")
+ col.prop(obj.pov, "no_image")
+ col.prop(obj.pov, "no_reflection")
+ col.prop(obj.pov, "no_radiosity")
+ col.prop(obj.pov, "inverse")
+ col.prop(obj.pov, "hierarchy")
+ # col.prop(obj.pov,"boundorclip",text="Bound / Clip")
+ # if obj.pov.boundorclip != "none":
+ # col.prop_search(obj.pov,"boundorclipob",context.blend_data,"objects",text="Object")
+ # text = "Clipped by"
+ # if obj.pov.boundorclip == "clipped_by":
+ # text = "Bounded by"
+ # col.prop(obj.pov,"addboundorclip",text=text)
+
+
+class OBJECT_PT_POV_obj_sphere(PovDataButtonsPanel, Panel):
+ """Use this class to define pov sphere primitive parameters buttons."""
+
+ bl_label = "POV Sphere"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ # bl_options = {'HIDE_HEADER'}
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ obj = context.object
+ return obj and obj.pov.object_as == 'SPHERE' and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ col = layout.column()
+
+ if obj.pov.object_as == 'SPHERE':
+ if not obj.pov.unlock_parameters:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+ )
+ col.label(text="Sphere radius: " + str(obj.pov.sphere_radius))
+
+ else:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+ )
+ col.label(text="3D view proxy may get out of synch")
+ col.active = obj.pov.unlock_parameters
+
+ layout.operator("pov.sphere_update", text="Update", icon="SHADING_RENDERED")
+
+ # col.label(text="Parameters:")
+ col.prop(obj.pov, "sphere_radius", text="Radius of Sphere")
+
+
+class OBJECT_PT_POV_obj_cylinder(PovDataButtonsPanel, Panel):
+ """Use this class to define pov cylinder primitive parameters buttons."""
+
+ bl_label = "POV Cylinder"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ # bl_options = {'HIDE_HEADER'}
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ obj = context.object
+ return obj and obj.pov.object_as == 'CYLINDER' and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ col = layout.column()
+
+ if obj.pov.object_as == 'CYLINDER':
+ if not obj.pov.unlock_parameters:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+ )
+ col.label(text="Cylinder radius: " + str(obj.pov.cylinder_radius))
+ col.label(text="Cylinder cap location: " + str(obj.pov.cylinder_location_cap))
+
+ else:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+ )
+ col.label(text="3D view proxy may get out of synch")
+ col.active = obj.pov.unlock_parameters
+
+ layout.operator("pov.cylinder_update", text="Update", icon="MESH_CYLINDER")
+
+ # col.label(text="Parameters:")
+ col.prop(obj.pov, "cylinder_radius")
+ col.prop(obj.pov, "cylinder_location_cap")
+
+
+class OBJECT_PT_POV_obj_cone(PovDataButtonsPanel, Panel):
+ """Use this class to define pov cone primitive parameters buttons."""
+
+ bl_label = "POV Cone"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ # bl_options = {'HIDE_HEADER'}
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ obj = context.object
+ return obj and obj.pov.object_as == 'CONE' and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ col = layout.column()
+
+ if obj.pov.object_as == 'CONE':
+ if not obj.pov.unlock_parameters:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+ )
+ col.label(text="Cone base radius: " + str(obj.pov.cone_base_radius))
+ col.label(text="Cone cap radius: " + str(obj.pov.cone_cap_radius))
+ col.label(text="Cone proxy segments: " + str(obj.pov.cone_segments))
+ col.label(text="Cone height: " + str(obj.pov.cone_height))
+ else:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+ )
+ col.label(text="3D view proxy may get out of synch")
+ col.active = obj.pov.unlock_parameters
+
+ layout.operator("pov.cone_update", text="Update", icon="MESH_CONE")
+
+ # col.label(text="Parameters:")
+ col.prop(obj.pov, "cone_base_radius", text="Radius of Cone Base")
+ col.prop(obj.pov, "cone_cap_radius", text="Radius of Cone Cap")
+ col.prop(obj.pov, "cone_segments", text="Segmentation of Cone proxy")
+ col.prop(obj.pov, "cone_height", text="Height of the cone")
+
+
+class OBJECT_PT_POV_obj_superellipsoid(PovDataButtonsPanel, Panel):
+ """Use this class to define pov superellipsoid primitive parameters buttons."""
+
+ bl_label = "POV Superquadric ellipsoid"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ # bl_options = {'HIDE_HEADER'}
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ obj = context.object
+ return obj and obj.pov.object_as == 'SUPERELLIPSOID' and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ col = layout.column()
+
+ if obj.pov.object_as == 'SUPERELLIPSOID':
+ if not obj.pov.unlock_parameters:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+ )
+ col.label(text="Radial segmentation: " + str(obj.pov.se_u))
+ col.label(text="Lateral segmentation: " + str(obj.pov.se_v))
+ col.label(text="Ring shape: " + str(obj.pov.se_n1))
+ col.label(text="Cross-section shape: " + str(obj.pov.se_n2))
+ col.label(text="Fill up and down: " + str(obj.pov.se_edit))
+ else:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+ )
+ col.label(text="3D view proxy may get out of synch")
+ col.active = obj.pov.unlock_parameters
+
+ layout.operator("pov.superellipsoid_update", text="Update", icon="MOD_SUBSURF")
+
+ # col.label(text="Parameters:")
+ col.prop(obj.pov, "se_u")
+ col.prop(obj.pov, "se_v")
+ col.prop(obj.pov, "se_n1")
+ col.prop(obj.pov, "se_n2")
+ col.prop(obj.pov, "se_edit")
+
+
+class OBJECT_PT_POV_obj_torus(PovDataButtonsPanel, Panel):
+ """Use this class to define pov torus primitive parameters buttons."""
+
+ bl_label = "POV Torus"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ # bl_options = {'HIDE_HEADER'}
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ obj = context.object
+ return obj and obj.pov.object_as == 'TORUS' and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ col = layout.column()
+
+ if obj.pov.object_as == 'TORUS':
+ if not obj.pov.unlock_parameters:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+ )
+ col.label(text="Torus major radius: " + str(obj.pov.torus_major_radius))
+ col.label(text="Torus minor radius: " + str(obj.pov.torus_minor_radius))
+ col.label(text="Torus major segments: " + str(obj.pov.torus_major_segments))
+ col.label(text="Torus minor segments: " + str(obj.pov.torus_minor_segments))
+ else:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+ )
+ col.label(text="3D view proxy may get out of synch")
+ col.active = obj.pov.unlock_parameters
+
+ layout.operator("pov.torus_update", text="Update", icon="MESH_TORUS")
+
+ # col.label(text="Parameters:")
+ col.prop(obj.pov, "torus_major_radius")
+ col.prop(obj.pov, "torus_minor_radius")
+ col.prop(obj.pov, "torus_major_segments")
+ col.prop(obj.pov, "torus_minor_segments")
+
+
+class OBJECT_PT_POV_obj_supertorus(PovDataButtonsPanel, Panel):
+ """Use this class to define pov supertorus primitive parameters buttons."""
+
+ bl_label = "POV SuperTorus"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ # bl_options = {'HIDE_HEADER'}
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ obj = context.object
+ return obj and obj.pov.object_as == 'SUPERTORUS' and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ col = layout.column()
+
+ if obj.pov.object_as == 'SUPERTORUS':
+ if not obj.pov.unlock_parameters:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+ )
+ col.label(text="SuperTorus major radius: " + str(obj.pov.st_major_radius))
+ col.label(text="SuperTorus minor radius: " + str(obj.pov.st_minor_radius))
+ col.label(text="SuperTorus major segments: " + str(obj.pov.st_u))
+ col.label(text="SuperTorus minor segments: " + str(obj.pov.st_v))
+
+ col.label(text="SuperTorus Ring Manipulator: " + str(obj.pov.st_ring))
+ col.label(text="SuperTorus Cross Manipulator: " + str(obj.pov.st_cross))
+ col.label(text="SuperTorus Internal And External radii: " + str(obj.pov.st_ie))
+
+ col.label(text="SuperTorus accuracy: " + str(obj.pov.st_accuracy))
+ col.label(text="SuperTorus max gradient: " + str(obj.pov.st_max_gradient))
+
+ else:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+ )
+ col.label(text="3D view proxy may get out of synch")
+ col.active = obj.pov.unlock_parameters
+
+ layout.operator("pov.supertorus_update", text="Update", icon="MESH_TORUS")
+
+ # col.label(text="Parameters:")
+ col.prop(obj.pov, "st_major_radius")
+ col.prop(obj.pov, "st_minor_radius")
+ col.prop(obj.pov, "st_u")
+ col.prop(obj.pov, "st_v")
+ col.prop(obj.pov, "st_ring")
+ col.prop(obj.pov, "st_cross")
+ col.prop(obj.pov, "st_ie")
+ # col.prop(obj.pov, "st_edit") #?
+ col.prop(obj.pov, "st_accuracy")
+ col.prop(obj.pov, "st_max_gradient")
+
+
+class OBJECT_PT_POV_obj_parametric(PovDataButtonsPanel, Panel):
+ """Use this class to define pov parametric surface primitive parameters buttons."""
+
+ bl_label = "POV Parametric surface"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ # bl_options = {'HIDE_HEADER'}
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ obj = context.object
+ return obj and obj.pov.object_as == 'PARAMETRIC' and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ col = layout.column()
+
+ if obj.pov.object_as == 'PARAMETRIC':
+ if not obj.pov.unlock_parameters:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+ )
+ col.label(text="Minimum U: " + str(obj.pov.u_min))
+ col.label(text="Minimum V: " + str(obj.pov.v_min))
+ col.label(text="Maximum U: " + str(obj.pov.u_max))
+ col.label(text="Minimum V: " + str(obj.pov.v_min))
+ col.label(text="X Function: " + str(obj.pov.x_eq))
+ col.label(text="Y Function: " + str(obj.pov.y_eq))
+ col.label(text="Z Function: " + str(obj.pov.x_eq))
+
+ else:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+ )
+ col.label(text="3D view proxy may get out of synch")
+ col.active = obj.pov.unlock_parameters
+
+ layout.operator("pov.parametric_update", text="Update", icon="SCRIPTPLUGINS")
+
+ col.prop(obj.pov, "u_min", text="Minimum U")
+ col.prop(obj.pov, "v_min", text="Minimum V")
+ col.prop(obj.pov, "u_max", text="Maximum U")
+ col.prop(obj.pov, "v_max", text="Minimum V")
+ col.prop(obj.pov, "x_eq", text="X Function")
+ col.prop(obj.pov, "y_eq", text="Y Function")
+ col.prop(obj.pov, "z_eq", text="Z Function")
+
+
+class OBJECT_PT_povray_replacement_text(ObjectButtonsPanel, Panel):
+ """Use this class to define pov object replacement field."""
+
+ bl_label = "Custom POV Code"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ col = layout.column()
+ col.label(text="Replace properties with:")
+ col.prop(obj.pov, "replacement_text", text="")
+
+
+###############################################################################
+# Add Povray Objects
+###############################################################################
+def check_add_mesh_extra_objects():
+ """Test if Add mesh extra objects addon is activated
+
+ This addon is currently used to generate the proxy for POV parametric
+ surface which is almost the same priciple as its Math xyz surface
+ """
+ if "add_mesh_extra_objects" in bpy.context.preferences.addons.keys():
+ return True
+ return False
+
+
+def menu_func_add(self, context):
+ """Append the POV primitives submenu to blender add objects menu"""
+ engine = context.scene.render.engine
+ if engine == 'POVRAY_RENDER':
+ self.layout.menu("VIEW_MT_POV_primitives_add", icon="PLUGIN")
+
+
+class VIEW_MT_POV_primitives_add(Menu):
+ """Define the primitives menu with presets"""
+
+ bl_idname = "VIEW_MT_POV_primitives_add"
+ bl_label = "Povray"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ return engine == 'POVRAY_RENDER'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.menu(VIEW_MT_POV_Basic_Shapes.bl_idname, text="Primitives", icon="GROUP")
+ layout.menu(VIEW_MT_POV_import.bl_idname, text="Import", icon="IMPORT")
+
+
+class VIEW_MT_POV_Basic_Shapes(Menu):
+ """Use this class to sort simple primitives menu entries."""
+
+ bl_idname = "POVRAY_MT_basic_shape_tools"
+ bl_label = "Basic_shapes"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("pov.addplane", text="Infinite Plane", icon='MESH_PLANE')
+ layout.operator("pov.addbox", text="Box", icon='MESH_CUBE')
+ layout.operator("pov.addsphere", text="Sphere", icon='SHADING_RENDERED')
+ layout.operator("pov.addcylinder", text="Cylinder", icon="MESH_CYLINDER")
+ layout.operator("pov.cone_add", text="Cone", icon="MESH_CONE")
+ layout.operator("pov.addtorus", text="Torus", icon='MESH_TORUS')
+ layout.separator()
+ layout.operator("pov.addrainbow", text="Rainbow", icon="COLOR")
+ layout.operator("pov.addlathe", text="Lathe", icon='MOD_SCREW')
+ layout.operator("pov.addprism", text="Prism", icon='MOD_SOLIDIFY')
+ layout.operator("pov.addsuperellipsoid", text="Superquadric Ellipsoid", icon='MOD_SUBSURF')
+ layout.operator("pov.addheightfield", text="Height Field", icon="RNDCURVE")
+ layout.operator("pov.addspheresweep", text="Sphere Sweep", icon='FORCE_CURVE')
+ layout.separator()
+ layout.operator("pov.addblobsphere", text="Blob Sphere", icon='META_DATA')
+ layout.separator()
+ layout.label(text="Isosurfaces")
+ layout.operator("pov.addisosurfacebox", text="Isosurface Box", icon="META_CUBE")
+ layout.operator("pov.addisosurfacesphere", text="Isosurface Sphere", icon="META_BALL")
+ layout.operator("pov.addsupertorus", text="Supertorus", icon="SURFACE_NTORUS")
+ layout.separator()
+ layout.label(text="Macro based")
+ layout.operator(
+ "pov.addpolygontocircle", text="Polygon To Circle Blending", icon="MOD_CAST"
+ )
+ layout.operator("pov.addloft", text="Loft", icon="SURFACE_NSURFACE")
+ layout.separator()
+ # Warning if the Add Advanced Objects addon containing
+ # Add mesh extra objects is not enabled
+ if not check_add_mesh_extra_objects():
+ # col = box.column()
+ layout.label(text="Please enable Add Mesh: Extra Objects addon", icon="INFO")
+ # layout.separator()
+ layout.operator(
+ "preferences.addon_show",
+ text="Go to Add Mesh: Extra Objects addon",
+ icon="PREFERENCES",
+ ).module = "add_mesh_extra_objects"
+
+ # layout.separator()
+ return
+ layout.operator("pov.addparametric", text="Parametric", icon='SCRIPTPLUGINS')
+
+
+classes = (
+ # ObjectButtonsPanel,
+ # PovDataButtonsPanel,
+ DATA_PT_POV_normals,
+ DATA_PT_POV_texture_space,
+ DATA_PT_POV_vertex_groups,
+ DATA_PT_POV_shape_keys,
+ DATA_PT_POV_uv_texture,
+ DATA_PT_POV_vertex_colors,
+ DATA_PT_POV_customdata,
+ MODIFIERS_PT_POV_modifiers,
+ OBJECT_PT_POV_obj_parameters,
+ OBJECT_PT_POV_obj_sphere,
+ OBJECT_PT_POV_obj_cylinder,
+ OBJECT_PT_POV_obj_cone,
+ OBJECT_PT_POV_obj_superellipsoid,
+ OBJECT_PT_POV_obj_torus,
+ OBJECT_PT_POV_obj_supertorus,
+ OBJECT_PT_POV_obj_parametric,
+ OBJECT_PT_povray_replacement_text,
+ VIEW_MT_POV_primitives_add,
+ VIEW_MT_POV_Basic_Shapes,
+)
+
+
+def register():
+ # from bpy.utils import register_class
+
+ for cls in classes:
+ register_class(cls)
+
+ bpy.types.VIEW3D_MT_add.prepend(menu_func_add)
+
+ # was used for parametric objects but made the other addon unreachable on
+ # unregister for other tools to use created a user action call instead
+ # addon_utils.enable("add_mesh_extra_objects", default_set=False, persistent=True)
+
+
+def unregister():
+ # addon_utils.disable("add_mesh_extra_objects", default_set=False)
+
+ bpy.types.VIEW3D_MT_add.remove(menu_func_add)
+
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/object_mesh_topology.py b/render_povray/object_mesh_topology.py
new file mode 100755
index 00000000..2b0ce008
--- /dev/null
+++ b/render_povray/object_mesh_topology.py
@@ -0,0 +1,1540 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""Translate to POV the control point compounded geometries like polygon
+
+meshes or curve based shapes."""
+
+####################
+## Faster mesh export
+import numpy as np
+
+####################
+import random # used for hair
+import bpy
+from . import texturing # for how textures influence shaders
+from .scenography import export_smoke
+
+
+def matrix_as_pov_string(matrix):
+ """Translate some tranform matrix from Blender UI
+ to POV syntax and return that string """
+ matrix_string = (
+ "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],
+ )
+ )
+ return matrix_string
+
+
+# objectNames = {}
+DEF_OBJ_NAME = "Default"
+
+
+def export_meshes(
+ preview_dir,
+ file,
+ scene,
+ sel,
+ csg,
+ string_strip_hyphen,
+ safety,
+ write_object_modifiers,
+ material_names_dictionary,
+ write_object_material,
+ exported_lights_count,
+ unpacked_images,
+ image_format,
+ img_map,
+ img_map_transforms,
+ path_image,
+ smoke_path,
+ global_matrix,
+ write_matrix,
+ using_uberpov,
+ comments,
+ linebreaksinlists,
+ tab,
+ tab_level,
+ tab_write,
+ info_callback,
+):
+ """write all meshes as POV mesh2{} syntax to exported file """
+ # some numpy functions to speed up mesh export NOT IN USE YET
+
+ # TODO: also write a numpy function to read matrices at object level?
+ # feed below with mesh object.data, but only after doing data.calc_loop_triangles()
+ def read_verts_co(self, mesh):
+ #'float64' would be a slower 64-bit floating-point number numpy datatype
+ # using 'float32' vert coordinates for now until any issue is reported
+ mverts_co = np.zeros((len(mesh.vertices) * 3), dtype=np.float32)
+ mesh.vertices.foreach_get("co", mverts_co)
+ return np.reshape(mverts_co, (len(mesh.vertices), 3))
+
+ def read_verts_idx(self, mesh):
+ mverts_idx = np.zeros((len(mesh.vertices)), dtype=np.int64)
+ mesh.vertices.foreach_get("index", mverts_idx)
+ return np.reshape(mverts_idx, (len(mesh.vertices), 1))
+
+ def read_verts_norms(self, mesh):
+ #'float64' would be a slower 64-bit floating-point number numpy datatype
+ # using less accurate 'float16' normals for now until any issue is reported
+ mverts_no = np.zeros((len(mesh.vertices) * 3), dtype=np.float16)
+ mesh.vertices.foreach_get("normal", mverts_no)
+ return np.reshape(mverts_no, (len(mesh.vertices), 3))
+
+ def read_faces_idx(self, mesh):
+ mfaces_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int64)
+ mesh.loop_triangles.foreach_get("index", mfaces_idx)
+ return np.reshape(mfaces_idx, (len(mesh.loop_triangles), 1))
+
+ def read_faces_verts_indices(self, mesh):
+ mfaces_verts_idx = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.int64)
+ mesh.loop_triangles.foreach_get("vertices", mfaces_verts_idx)
+ return np.reshape(mfaces_verts_idx, (len(mesh.loop_triangles), 3))
+
+ # Why is below different from vertex indices?
+ def read_faces_verts_loops(self, mesh):
+ mfaces_verts_loops = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.int64)
+ mesh.loop_triangles.foreach_get("loops", mfaces_verts_loops)
+ return np.reshape(mfaces_verts_loops, (len(mesh.loop_triangles), 3))
+
+ def read_faces_norms(self, mesh):
+ #'float64' would be a slower 64-bit floating-point number numpy datatype
+ # using less accurate 'float16' normals for now until any issue is reported
+ mfaces_no = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.float16)
+ mesh.loop_triangles.foreach_get("normal", mfaces_no)
+ return np.reshape(mfaces_no, (len(mesh.loop_triangles), 3))
+
+ def read_faces_smooth(self, mesh):
+ mfaces_smth = np.zeros((len(mesh.loop_triangles) * 1), dtype=np.bool)
+ mesh.loop_triangles.foreach_get("use_smooth", mfaces_smth)
+ return np.reshape(mfaces_smth, (len(mesh.loop_triangles), 1))
+
+ def read_faces_material_indices(self, mesh):
+ mfaces_mats_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int16)
+ mesh.loop_triangles.foreach_get("material_index", mfaces_mats_idx)
+ return np.reshape(mfaces_mats_idx, (len(mesh.loop_triangles), 1))
+
+ # obmatslist = []
+ # def hasUniqueMaterial():
+ # # Grab materials attached to object instances ...
+ # if hasattr(ob, 'material_slots'):
+ # for ms in ob.material_slots:
+ # if ms.material is not None and ms.link == 'OBJECT':
+ # if ms.material in obmatslist:
+ # return False
+ # else:
+ # obmatslist.append(ms.material)
+ # return True
+ # def hasObjectMaterial(ob):
+ # # Grab materials attached to object instances ...
+ # if hasattr(ob, 'material_slots'):
+ # for ms in ob.material_slots:
+ # if ms.material is not None and ms.link == 'OBJECT':
+ # # If there is at least one material slot linked to the object
+ # # and not the data (mesh), always create a new, "private" data instance.
+ # return True
+ # return False
+ # For objects using local material(s) only!
+ # This is a mapping between a tuple (dataname, material_names_dictionary, ...), and the POV dataname.
+ # As only objects using:
+ # * The same data.
+ # * EXACTLY the same materials, in EXACTLY the same sockets.
+ # ... can share a same instance in POV export.
+ obmats2data = {}
+
+ def check_object_materials(ob, name, dataname):
+ """Compare other objects exported material slots to avoid rewriting duplicates"""
+ if hasattr(ob, 'material_slots'):
+ has_local_mats = False
+ key = [dataname]
+ for ms in ob.material_slots:
+ if ms.material is not None:
+ key.append(ms.material.name)
+ if ms.link == 'OBJECT' and not has_local_mats:
+ has_local_mats = True
+ else:
+ # Even if the slot is empty, it is important to grab it...
+ key.append("")
+ if has_local_mats:
+ # If this object uses local material(s), lets find if another object
+ # using the same data and exactly the same list of materials
+ # (in the same slots) has already been processed...
+ # Note that here also, we use object name as new, unique dataname for Pov.
+ key = tuple(key) # Lists are not hashable...
+ if key not in obmats2data:
+ obmats2data[key] = name
+ return obmats2data[key]
+ return None
+
+ data_ref = {}
+
+ def store(scene, ob, name, dataname, matrix):
+ # The Object needs to be written at least once but if its data is
+ # already in data_ref this has already been done.
+ # This func returns the "povray" name of the data, or None
+ # if no writing is needed.
+ if ob.is_modified(scene, 'RENDER'):
+ # Data modified.
+ # Create unique entry in data_ref by using object name
+ # (always unique in Blender) as data name.
+ data_ref[name] = [(name, matrix_as_pov_string(matrix))]
+ return name
+ # Here, we replace dataname by the value returned by check_object_materials, only if
+ # it is not evaluated to False (i.e. only if the object uses some local material(s)).
+ dataname = check_object_materials(ob, name, dataname) or dataname
+ if dataname in data_ref:
+ # Data already known, just add the object instance.
+ data_ref[dataname].append((name, matrix_as_pov_string(matrix)))
+ # No need to write data
+ return None
+ # Else (no return yet): Data not yet processed, create a new entry in data_ref.
+ data_ref[dataname] = [(name, matrix_as_pov_string(matrix))]
+ return dataname
+
+ # XXX TODO : Too many nested blocks in this object loop, split hair (+particles?) to their function in own file,
+ ob_num = 0
+ for ob in sel:
+ # Using depsgraph
+ depsgraph = bpy.context.evaluated_depsgraph_get()
+ ob = bpy.data.objects[ob.name].evaluated_get(depsgraph)
+
+ # 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
+ fluid_flag = False
+ for mod in ob.modifiers:
+ if mod and hasattr(mod, 'fluid_type'):
+ fluid_flag = True
+ if mod.fluid_type == 'DOMAIN':
+ if mod.domain_settings.domain_type == 'GAS':
+ export_smoke(
+ file, ob.name, smoke_path, comments, global_matrix, write_matrix
+ )
+ break # don't render domain mesh, skip to next object.
+ if mod.fluid_type == 'FLOW': # The domain contains all the smoke. so that's it.
+ if mod.flow_settings.flow_type == 'SMOKE': # Check how liquids behave
+ break # don't render smoke flow emitter mesh either, skip to next object.
+ if not fluid_flag:
+ # Export Hair
+ # importing here rather than at the top recommended for addons startup footprint
+ from .object_particles import export_hair
+
+ render_emitter = True
+ if hasattr(ob, 'particle_systems'):
+ render_emitter = False
+ if ob.show_instancer_for_render:
+ render_emitter = True
+ for p_sys in ob.particle_systems:
+ for mod in [
+ m
+ for m in ob.modifiers
+ if (m is not None) and (m.type == 'PARTICLE_SYSTEM')
+ ]:
+ if (
+ (p_sys.settings.render_type == 'PATH')
+ and mod.show_render
+ and (p_sys.name == mod.particle_system.name)
+ ):
+ export_hair(file, ob, p_sys, global_matrix, write_matrix)
+ if not render_emitter:
+ 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:
+ 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:
+ # Real dupli instance filtered because
+ # original included in list since 2.8
+ if eachduplicate.is_instance:
+ 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
+ else:
+ 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
+
+ print("Writing Down First Occurrence of " + name)
+
+ ############################################Povray Primitives
+ # special export_curves() 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':
+ tab_write("#declare %s = isosurface{ \n" % povdataname)
+ tab_write("function{ \n")
+ text_name = ob.pov.iso_function_text
+ if text_name:
+ 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:
+ tab_write(
+ "#declare %s = %.6g;\n" % (inp.name, inp.default_value)
+ )
+
+ text = bpy.data.texts[text_name]
+ for line in text.lines:
+ split = line.body.split()
+ if split[0] != "#declare":
+ tab_write("%s\n" % line.body)
+ else:
+ tab_write("abs(x) - 2 + y")
+ tab_write("}\n")
+ tab_write("threshold %.6g\n" % ob.pov.threshold)
+ tab_write("max_gradient %.6g\n" % ob.pov.max_gradient)
+ tab_write("accuracy %.6g\n" % ob.pov.accuracy)
+ tab_write("contained_by { ")
+ if ob.pov.contained_by == "sphere":
+ tab_write("sphere {0,%.6g}}\n" % ob.pov.container_scale)
+ else:
+ tab_write(
+ "box {-%.6g,%.6g}}\n" % (ob.pov.container_scale, ob.pov.container_scale)
+ )
+ if ob.pov.all_intersections:
+ tab_write("all_intersections\n")
+ else:
+ if ob.pov.max_trace > 1:
+ tab_write("max_trace %.6g\n" % ob.pov.max_trace)
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ tab_write("scale %.6g\n" % (1 / ob.pov.container_scale))
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ if ob.pov.object_as == 'SUPERELLIPSOID':
+ tab_write(
+ "#declare %s = superellipsoid{ <%.4f,%.4f>\n"
+ % (povdataname, ob.pov.se_n2, ob.pov.se_n1)
+ )
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ write_object_modifiers(scene, ob, file)
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ if ob.pov.object_as == 'SUPERTORUS':
+ rad_maj = ob.pov.st_major_radius
+ rad_min = 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")
+ ############
+ tab_write(
+ "#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n"
+ % (povdataname, rad_maj, rad_min, ring, cross, accuracy, gradient)
+ )
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ write_object_modifiers(scene, ob, file)
+ tab_write("rotate x*90\n")
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ if ob.pov.object_as == 'PLANE':
+ tab_write("#declare %s = plane{ <0,0,1>,1\n" % povdataname)
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ write_object_modifiers(scene, ob, file)
+ # tab_write("rotate x*90\n")
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ if ob.pov.object_as == 'BOX':
+ tab_write("#declare %s = box { -1,1\n" % povdataname)
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ write_object_modifiers(scene, ob, file)
+ # tab_write("rotate x*90\n")
+ tab_write("}\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
+ tab_write(
+ "#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n"
+ % (povdataname, bz, br, cz, cr)
+ )
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ write_object_modifiers(scene, ob, file)
+ # tab_write("rotate x*90\n")
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ 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]
+ tab_write(
+ "#declare %s = cylinder { <0,0,0>,<%6f,%6f,%6f>,%6f\n"
+ % (povdataname, x2, y2, z2, r)
+ )
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ # cylinders written at origin, translated below
+ write_object_modifiers(scene, ob, file)
+ # tab_write("rotate x*90\n")
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ 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
+ tab_write('#declare %s = height_field { %s\n' % (povdataname, data))
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ write_object_modifiers(scene, ob, file)
+ tab_write("rotate x*90\n")
+ tab_write("translate <-0.5,0.5,0>\n")
+ tab_write("scale <0,-1,0>\n")
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ if ob.pov.object_as == 'SPHERE':
+
+ tab_write(
+ "#declare %s = sphere { 0,%6f\n" % (povdataname, ob.pov.sphere_radius)
+ )
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ write_object_modifiers(scene, ob, file)
+ # tab_write("rotate x*90\n")
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ if ob.pov.object_as == 'TORUS':
+ tab_write(
+ "#declare %s = torus { %.4f,%.4f\n"
+ % (povdataname, ob.pov.torus_major_radius, ob.pov.torus_minor_radius)
+ )
+ pov_mat_name = "Default_texture"
+ if ob.active_material:
+ # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+ try:
+ material = ob.active_material
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ write_object_modifiers(scene, ob, file)
+ tab_write("rotate x*90\n")
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ if ob.pov.object_as == 'PARAMETRIC':
+ tab_write("#declare %s = parametric {\n" % povdataname)
+ tab_write("function { %s }\n" % ob.pov.x_eq)
+ tab_write("function { %s }\n" % ob.pov.y_eq)
+ tab_write("function { %s }\n" % ob.pov.z_eq)
+ tab_write(
+ "<%.4f,%.4f>, <%.4f,%.4f>\n"
+ % (ob.pov.u_min, ob.pov.v_min, ob.pov.u_max, ob.pov.v_max)
+ )
+ # Previous to 3.8 default max_gradient 1.0 was too slow
+ tab_write("max_gradient 0.001\n")
+ if ob.pov.contained_by == "sphere":
+ tab_write("contained_by { sphere{0, 2} }\n")
+ else:
+ tab_write("contained_by { box{-2, 2} }\n")
+ tab_write("max_gradient %.6f\n" % ob.pov.max_gradient)
+ tab_write("accuracy %.6f\n" % ob.pov.accuracy)
+ tab_write("precompute 10 x,y,z\n")
+ tab_write("}\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
+ tab_write(
+ "#declare %s = object { Shape_Polygon_To_Circle_Blending(%s, z, %.4f, %.4f, 2) rotate x*180 translate z*1\n"
+ % (povdataname, ngon, ngonR, circleR)
+ )
+ tab_write("}\n")
+ continue # Don't render proxy mesh, skip to next object
+
+ ## In remaining cases; keep at end so no "elif" is needed,
+ # (as not skipped by any previous "continue")
+ # and for originals not their instances,
+ # attempt to export mesh:
+ if not ob.is_instancer:
+ # except duplis which should be instances groups for now but all duplis later
+ if ob.type == 'EMPTY':
+ # XXX Should we only write this once and instanciate the same for every
+ # empty in the final matrix writing, or even no marix and just a comment
+ # with empty object transforms ?
+ tab_write("\n//dummy sphere to represent Empty location\n")
+ tab_write(
+ "#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 # Don't render empty object but this is later addition, watch it.
+
+ depsgraph = bpy.context.evaluated_depsgraph_get()
+ ob_eval = ob.evaluated_get(depsgraph)
+ try:
+ me = ob_eval.to_mesh()
+
+ # Here identify the exception for mesh object with no data: Runtime-Error ?
+ # So we can write something for the dataname or maybe treated "if not me" below
+ except BaseException as e:
+ print(e.__doc__)
+ print('An exception occurred: {}'.format(e))
+ # 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[:]
+ ## numpytest
+ # me_looptris = me.loops
+
+ ## otypes = ['int32'] is a 32-bit signed integer number numpy datatype
+ # get_v_index = np.vectorize(lambda l: l.vertex_index, otypes = ['int32'], cache = True)
+ # faces_verts_idx = get_v_index(me_looptris)
+
+ # if len(me_faces)==0:
+ # tab_write("\n//dummy sphere to represent empty mesh location\n")
+ # tab_write("#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:
+ tab_write("\n//dummy sphere to represent empty mesh location\n")
+ tab_write(
+ "#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
+ else:
+ uv_layer = None
+
+ 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")
+ tab_write("#declare %s =\n" % povdataname)
+ tab_write("mesh2 {\n")
+ tab_write("vertex_vectors {\n")
+ tab_write("%d" % len(me.vertices)) # vert count
+
+ tab_str = tab * tab_level
+ for v in me.vertices:
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(tab_str + "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
+ else:
+ file.write(", ")
+ file.write("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
+ # tab_write("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
+ file.write("\n")
+ tab_write("}\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]
+
+ tab_write("normal_vectors {\n")
+ tab_write("%d" % len(uniqueNormals)) # vert count
+ idx = 0
+ tab_str = tab * tab_level
+ for no, index in uniqueNormals.items():
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(tab_str + "<%.6f, %.6f, %.6f>" % no) # vert count
+ else:
+ file.write(", ")
+ file.write("<%.6f, %.6f, %.6f>" % no) # vert count
+ index[0] = idx
+ idx += 1
+ file.write("\n")
+ tab_write("}\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]
+
+ tab_write("uv_vectors {\n")
+ # print unique_uvs
+ tab_write("%d" % len(uniqueUVs)) # vert count
+ idx = 0
+ tab_str = tab * tab_level
+ for uv, index in uniqueUVs.items():
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(tab_str + "<%.6f, %.6f>" % uv)
+ else:
+ file.write(", ")
+ file.write("<%.6f, %.6f>" % uv)
+ index[0] = idx
+ idx += 1
+ '''
+ else:
+ # Just add 1 dummy vector, no real UV's
+ tab_write('1') # vert count
+ file.write(',\n\t\t<0.0, 0.0>')
+ '''
+ file.write("\n")
+ tab_write("}\n")
+
+ if me.vertex_colors:
+ # Write down vertex colors as a texture for each vertex
+ tab_write("texture_list {\n")
+ tab_write("%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 BaseException as e:
+ print(e.__doc__)
+ print('An exception occurred: {}'.format(e))
+ 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:
+ tab_write(
+ "texture {pigment{ color srgb <%6f,%6f,%6f> }}\n"
+ % (col[0], col[1], col[2])
+ )
+ else:
+ tab_write(
+ "texture {pigment{ color srgb <%6f,%6f,%6f> }}"
+ % (col[0], col[1], col[2])
+ )
+ tab_str = tab * tab_level
+ else:
+ 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]
+
+ tab_write("\n}\n")
+ # Face indices
+ tab_write("\nface_indices {\n")
+ tab_write("%d" % (len(me_faces))) # faces count
+ tab_str = tab * tab_level
+
+ 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(tab_str + "<%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
+ 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]
+
+ 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(
+ tab_str
+ + "<%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")
+ tab_write("}\n")
+
+ # normal_indices indices
+ tab_write("normal_indices {\n")
+ tab_write("%d" % (len(me_faces))) # faces count
+ tab_str = tab * tab_level
+ for fi, fv in enumerate(faces_verts):
+
+ if me_faces[fi].use_smooth:
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(
+ tab_str
+ + "<%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
+ else:
+ idx = uniqueNormals[faces_normals[fi]][0]
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(
+ tab_str + "<%d,%d,%d>" % (idx, idx, idx)
+ ) # vert count
+ else:
+ file.write(", ")
+ file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
+
+ file.write("\n")
+ tab_write("}\n")
+
+ if uv_layer:
+ tab_write("uv_indices {\n")
+ tab_write("%d" % (len(me_faces))) # faces count
+ tab_str = tab * tab_level
+ for f in me_faces:
+ uvs = [uv_layer[l].uv[:] for l in f.loops]
+
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(
+ tab_str
+ + "<%d,%d,%d>"
+ % (
+ uniqueUVs[uvs[0]][0],
+ uniqueUVs[uvs[1]][0],
+ uniqueUVs[uvs[2]][0],
+ )
+ )
+ else:
+ file.write(", ")
+ file.write(
+ "<%d,%d,%d>"
+ % (
+ uniqueUVs[uvs[0]][0],
+ uniqueUVs[uvs[1]][0],
+ uniqueUVs[uvs[2]][0],
+ )
+ )
+
+ file.write("\n")
+ tab_write("}\n")
+
+ # XXX BOOLEAN
+ onceCSG = 0
+ for mod in ob.modifiers:
+ if onceCSG == 0:
+ if mod:
+ if mod.type == 'BOOLEAN':
+ if ob.pov.boolean_mod == "POV":
+ file.write(
+ "\tinside_vector <%.6g, %.6g, %.6g>\n"
+ % (
+ ob.pov.inside_vector[0],
+ ob.pov.inside_vector[1],
+ ob.pov.inside_vector[2],
+ )
+ )
+ onceCSG = 1
+
+ if me.materials:
+ try:
+ material = me.materials[0] # dodgy
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+
+ # POV object modifiers such as
+ # hollow / sturm / double_illuminate etc.
+ write_object_modifiers(scene, ob, file)
+
+ # Importance for radiosity sampling added here:
+ tab_write("radiosity { \n")
+ tab_write("importance %3g \n" % importance)
+ tab_write("}\n")
+
+ tab_write("}\n") # End of mesh block
+ else:
+ facesMaterials = [] # WARNING!!!!!!!!!!!!!!!!!!!!!!
+ if me_materials:
+ for f in me_faces:
+ if f.material_index not in facesMaterials:
+ facesMaterials.append(f.material_index)
+ # No vertex colors, so write material colors as vertex colors
+ for i, material in enumerate(me_materials):
+
+ if (
+ material and material.pov.material_use_nodes == False
+ ): # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ # 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],
+ i,
+ ) # i == f.mat
+ vertCols[key] = [-1]
+ else:
+ diffuse_color = material.diffuse_color[:]
+ key = (
+ diffuse_color[0],
+ diffuse_color[1],
+ diffuse_color[2],
+ i,
+ ) # i == f.mat
+ vertCols[key] = [-1]
+
+ idx = 0
+ local_material_names = []
+ for col, index in vertCols.items():
+ # if me_materials:
+ mater = me_materials[col[3]]
+ if me_materials is None: # XXX working?
+ material_finish = DEF_MAT_NAME # not working properly,
+ trans = 0.0
+
+ else:
+ texturing.write_texture_influence(
+ using_uberpov,
+ mater,
+ material_names_dictionary,
+ local_material_names,
+ path_image,
+ exported_lights_count,
+ image_format,
+ img_map,
+ img_map_transforms,
+ tab_write,
+ comments,
+ string_strip_hyphen,
+ safety,
+ col,
+ preview_dir,
+ unpacked_images,
+ )
+ ###################################################################
+ index[0] = idx
+ idx += 1
+
+ # Vert Colors
+ tab_write("texture_list {\n")
+ # In case there's is no material slot, give at least one texture
+ # (an empty one so it uses pov default)
+ if len(vertCols) == 0:
+ file.write(tab_str + "1")
+ else:
+ file.write(tab_str + "%s" % (len(vertCols))) # vert count
+
+ # below "material" alias, added check ob.active_material
+ # to avoid variable referenced before assignment error
+ try:
+ material = ob.active_material
+ except IndexError:
+ # when no material slot exists,
+ material = None
+
+ # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ if (
+ material
+ and ob.active_material is not None
+ and material.pov.material_use_nodes == False
+ ):
+ if material.pov.replacement_text != "":
+ file.write("\n")
+ file.write(" texture{%s}\n" % material.pov.replacement_text)
+
+ else:
+ # Loop through declared materials list
+ for cMN in local_material_names:
+ if material != "Default":
+ file.write("\n texture{MAT_%s}\n" % cMN)
+ # use string_strip_hyphen(material_names_dictionary[material]))
+ # or Something like that to clean up the above?
+ elif material and material.pov.material_use_nodes:
+ for index in facesMaterials:
+ faceMaterial = string_strip_hyphen(
+ bpy.path.clean_name(me_materials[index].name)
+ )
+ file.write("\n texture{%s}\n" % faceMaterial)
+ # END!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ else:
+ file.write(" texture{}\n")
+ tab_write("}\n")
+
+ # Face indices
+ tab_write("face_indices {\n")
+ tab_write("%d" % (len(me_faces))) # faces count
+ tab_str = tab * tab_level
+
+ 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(tab_str + "<%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
+ else:
+ material = me_materials[material_index]
+ ci1 = ci2 = ci3 = f.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]
+
+ 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]
+ elif material.pov.material_use_nodes:
+ ci1 = ci2 = ci3 = 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]
+
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(
+ tab_str
+ + "<%d,%d,%d>, %d,%d,%d"
+ % (fv[0], fv[1], fv[2], ci1, ci2, ci3)
+ ) # vert count
+ else:
+ file.write(", ")
+ file.write(
+ "<%d,%d,%d>, %d,%d,%d"
+ % (fv[0], fv[1], fv[2], ci1, ci2, ci3)
+ ) # vert count
+
+ file.write("\n")
+ tab_write("}\n")
+
+ # normal_indices indices
+ tab_write("normal_indices {\n")
+ tab_write("%d" % (len(me_faces))) # faces count
+ tab_str = tab * tab_level
+ for fi, fv in enumerate(faces_verts):
+ if me_faces[fi].use_smooth:
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(
+ tab_str
+ + "<%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
+ else:
+ idx = uniqueNormals[faces_normals[fi]][0]
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(
+ tab_str + "<%d,%d,%d>" % (idx, idx, idx)
+ ) # vertcount
+ else:
+ file.write(", ")
+ file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
+
+ file.write("\n")
+ tab_write("}\n")
+
+ if uv_layer:
+ tab_write("uv_indices {\n")
+ tab_write("%d" % (len(me_faces))) # faces count
+ tab_str = tab * tab_level
+ for f in me_faces:
+ uvs = [uv_layer[l].uv[:] for l in f.loops]
+
+ if linebreaksinlists:
+ file.write(",\n")
+ file.write(
+ tab_str
+ + "<%d,%d,%d>"
+ % (
+ uniqueUVs[uvs[0]][0],
+ uniqueUVs[uvs[1]][0],
+ uniqueUVs[uvs[2]][0],
+ )
+ )
+ else:
+ file.write(", ")
+ file.write(
+ "<%d,%d,%d>"
+ % (
+ uniqueUVs[uvs[0]][0],
+ uniqueUVs[uvs[1]][0],
+ uniqueUVs[uvs[2]][0],
+ )
+ )
+
+ file.write("\n")
+ tab_write("}\n")
+
+ # XXX BOOLEAN
+ onceCSG = 0
+ for mod in ob.modifiers:
+ if onceCSG == 0:
+ if mod:
+ if mod.type == 'BOOLEAN':
+ if ob.pov.boolean_mod == "POV":
+ file.write(
+ "\tinside_vector <%.6g, %.6g, %.6g>\n"
+ % (
+ ob.pov.inside_vector[0],
+ ob.pov.inside_vector[1],
+ ob.pov.inside_vector[2],
+ )
+ )
+ onceCSG = 1
+
+ if me.materials:
+ try:
+ material = me.materials[0] # dodgy
+ write_object_material(material, ob, tab_write)
+ except IndexError:
+ print(me)
+
+ # POV object modifiers such as
+ # hollow / sturm / double_illuminate etc.
+ write_object_modifiers(scene, ob, file)
+
+ # Importance for radiosity sampling added here:
+ tab_write("radiosity { \n")
+ tab_write("importance %3g \n" % importance)
+ tab_write("}\n")
+
+ tab_write("}\n") # End of mesh block
+
+ ob_eval.to_mesh_clear()
+
+ if csg:
+ duplidata_ref = []
+ _dupnames_seen = dict() # avoid duplicate output during introspection
+ for ob in sel:
+ # matrix = global_matrix @ ob.matrix_world
+ if ob.is_instancer:
+ tab_write("\n//--DupliObjects in %s--\n\n" % ob.name)
+ # ob.dupli_list_create(scene) #deprecated in 2.8
+ depsgraph = bpy.context.evaluated_depsgraph_get()
+ dup = ""
+ if ob.is_modified(scene, 'RENDER'):
+ # modified object always unique so using object name rather than data name
+ dup = "#declare OB%s = union{\n" % (
+ string_strip_hyphen(bpy.path.clean_name(ob.name))
+ )
+ else:
+ dup = "#declare DATA%s = union{\n" % (
+ string_strip_hyphen(bpy.path.clean_name(ob.name))
+ )
+ for eachduplicate in depsgraph.object_instances:
+ if (
+ eachduplicate.is_instance
+ ): # Real dupli instance filtered because original included in list since 2.8
+ _dupname = eachduplicate.object.name
+ _dupobj = bpy.data.objects[_dupname]
+ # BEGIN introspection for troubleshooting purposes
+ if not "name" in dir(_dupobj.data):
+ if _dupname not in _dupnames_seen:
+ print(
+ "WARNING: bpy.data.objects[%s].data (of type %s) has no 'name' attribute"
+ % (_dupname, type(_dupobj.data))
+ )
+ for _thing in dir(_dupobj):
+ print(
+ "|| %s.%s = %s"
+ % (_dupname, _thing, getattr(_dupobj, _thing))
+ )
+ _dupnames_seen[_dupname] = 1
+ print("''=> Unparseable objects so far: %s" % (_dupnames_seen))
+ else:
+ _dupnames_seen[_dupname] += 1
+ continue # don't try to parse data objects with no name attribute
+ # END introspection for troubleshooting purposes
+ duplidataname = "OB" + string_strip_hyphen(
+ bpy.path.clean_name(_dupobj.data.name)
+ )
+ dupmatrix = (
+ eachduplicate.matrix_world.copy()
+ ) # has to be copied to not store instance since 2.8
+ dup += "\tobject {\n\t\tDATA%s\n\t\t%s\t}\n" % (
+ string_strip_hyphen(bpy.path.clean_name(_dupobj.data.name)),
+ matrix_as_pov_string(ob.matrix_world.inverted() @ dupmatrix),
+ )
+ # add object to a list so that it is not rendered for some instance_types
+ if (
+ ob.instance_type not in {'COLLECTION'}
+ and duplidataname not in duplidata_ref
+ ):
+ duplidata_ref.append(
+ duplidataname
+ ) # older key [string_strip_hyphen(bpy.path.clean_name("OB"+ob.name))]
+ dup += "}\n"
+ # ob.dupli_list_clear()# just do not store any reference to instance since 2.8
+ tab_write(dup)
+ else:
+ continue
+ print("WARNING: Unparseable objects in current .blend file:\n''=> %s" % (_dupnames_seen))
+ print("duplidata_ref = %s" % (duplidata_ref))
+ for data_name, inst in data_ref.items():
+ for ob_name, matrix_str in inst:
+ if ob_name not in duplidata_ref: # .items() for a dictionary
+ tab_write("\n//----Blender Object Name:%s----\n" % ob_name)
+ if ob.pov.object_as == '':
+ tab_write("object { \n")
+ tab_write("%s\n" % data_name)
+ tab_write("%s\n" % matrix_str)
+ tab_write("}\n")
+ else:
+ no_boolean = True
+ for mod in ob.modifiers:
+ if mod.type == 'BOOLEAN':
+ operation = None
+ no_boolean = False
+ if mod.operation == 'INTERSECT':
+ operation = 'intersection'
+ else:
+ operation = mod.operation.lower()
+ mod_ob_name = string_strip_hyphen(
+ bpy.path.clean_name(mod.object.name)
+ )
+ mod_matrix = global_matrix @ mod.object.matrix_world
+ mod_ob_matrix = matrix_as_pov_string(mod_matrix)
+ tab_write("%s { \n" % operation)
+ tab_write("object { \n")
+ tab_write("%s\n" % data_name)
+ tab_write("%s\n" % matrix_str)
+ tab_write("}\n")
+ tab_write("object { \n")
+ tab_write("%s\n" % ('DATA' + mod_ob_name))
+ tab_write("%s\n" % mod_ob_matrix)
+ tab_write("}\n")
+ tab_write("}\n")
+ break
+ if no_boolean:
+ tab_write("object { \n")
+ tab_write("%s\n" % data_name)
+ tab_write("%s\n" % matrix_str)
+ tab_write("}\n")
diff --git a/render_povray/object_particles.py b/render_povray/object_particles.py
new file mode 100755
index 00000000..2d4f0dcc
--- /dev/null
+++ b/render_povray/object_particles.py
@@ -0,0 +1,255 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Get some Blender particle objects translated to POV."""
+
+import bpy
+
+
+def export_hair(file, ob, p_sys, global_matrix, write_matrix):
+ """Get Blender path particles (hair strands) objects translated to POV sphere_sweep unions."""
+ # tstart = time.time()
+ textured_hair = 0
+ if ob.material_slots[p_sys.settings.material - 1].material and ob.active_material is not None:
+ pmaterial = ob.material_slots[p_sys.settings.material - 1].material
+ # XXX Todo: replace by pov_(Particles?)_texture_slot
+ for th in pmaterial.pov_texture_slots:
+ povtex = th.texture # slot.name
+ tex = bpy.data.textures[povtex]
+
+ if th and th.use:
+ if (tex.type == 'IMAGE' and tex.image) or tex.type != 'IMAGE':
+ if th.use_map_color_diffuse:
+ textured_hair = 1
+ if pmaterial.strand.use_blender_units:
+ strand_start = pmaterial.strand.root_size
+ strand_end = pmaterial.strand.tip_size
+ strand_shape = pmaterial.strand.shape
+ else: # Blender unit conversion
+ strand_start = pmaterial.strand.root_size / 200.0
+ strand_end = pmaterial.strand.tip_size / 200.0
+ strand_shape = pmaterial.strand.shape
+ else:
+ pmaterial = "default" # No material assigned in blender, use default one
+ strand_start = 0.01
+ strand_end = 0.01
+ strand_shape = 0.0
+ # Set the number of particles to render count rather than 3d view display
+ # p_sys.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,
+ # it's automatic now.
+ steps = p_sys.settings.display_step
+ steps = 2 ** steps # or + 1 # Formerly : len(particle.hair_keys)
+
+ total_number_of_strands = p_sys.settings.count + p_sys.settings.rendered_child_count
+ # hairCounter = 0
+ file.write('#declare HairArray = array[%i] {\n' % total_number_of_strands)
+ for pindex in range(0, total_number_of_strands):
+
+ # 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 p_sys.settings.use_hair_bspline:
+ file.write('b_spline ')
+ file.write(
+ '%i,\n' % (steps + 2)
+ ) # +2 because the first point needs tripling to be more than a handle in POV
+ else:
+ file.write('linear_spline ')
+ file.write('%i,\n' % (steps))
+ # changing world coordinates to object local coordinates by
+ # multiplying with inverted matrix
+ init_coord = ob.matrix_world.inverted() @ (p_sys.co_hair(ob, particle_no=pindex, step=0))
+ if (
+ ob.material_slots[p_sys.settings.material - 1].material
+ and ob.active_material is not None
+ ):
+ pmaterial = ob.material_slots[p_sys.settings.material - 1].material
+ for th in pmaterial.pov_texture_slots:
+ if th and th.use and th.use_map_color_diffuse:
+ povtex = th.texture # slot.name
+ tex = bpy.data.textures[povtex]
+ # treat POV textures as bitmaps
+ if (
+ tex.type == 'IMAGE'
+ and tex.image
+ and th.texture_coords == 'UV'
+ and ob.data.uv_textures is not None
+ ):
+ # or (
+ # tex.pov.tex_pattern_type != 'emulator'
+ # and th.texture_coords == 'UV'
+ # and ob.data.uv_textures is not None
+ # ):
+ image = tex.image
+ image_width = image.size[0]
+ image_height = image.size[1]
+ image_pixels = image.pixels[:]
+ uv_co = p_sys.uv_on_emitter(mod, p_sys.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]
+ init_color = (r, g, b, a)
+ else:
+ # only overwrite variable for each competing texture for now
+ init_color = tex.evaluate((init_coord[0], init_coord[1], init_coord[2]))
+ for step in range(0, steps):
+ coord = ob.matrix_world.inverted() @ (p_sys.co_hair(ob, particle_no=pindex, step=step))
+ # for controlPoint in particle.hair_keys:
+ if p_sys.settings.clump_factor != 0:
+ hair_strand_diameter = p_sys.settings.clump_factor / 200.0 * random.uniform(0.5, 1)
+ elif step == 0:
+ hair_strand_diameter = strand_start
+ else:
+ hair_strand_diameter += (strand_end - strand_start) / (
+ p_sys.settings.display_step + 1
+ ) # XXX +1 or not? # XXX use strand_shape in formula
+ if step == 0 and p_sys.settings.use_hair_bspline:
+ # Write three times the first point to compensate pov Bezier handling
+ file.write(
+ '<%.6g,%.6g,%.6g>,%.7g,\n'
+ % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
+ )
+ file.write(
+ '<%.6g,%.6g,%.6g>,%.7g,\n'
+ % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
+ )
+ # Useless because particle location is the tip, not the root:
+ # file.write(
+ # '<%.6g,%.6g,%.6g>,%.7g'
+ # % (
+ # particle.location[0],
+ # particle.location[1],
+ # particle.location[2],
+ # abs(hair_strand_diameter)
+ # )
+ # )
+ # file.write(',\n')
+ # controlPointCounter += 1
+ # total_number_of_strands += len(p_sys.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' % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
+ )
+
+ # All coordinates except the last need a following comma.
+
+ if step != steps - 1:
+ file.write(',\n')
+ else:
+ if textured_hair:
+ # Write pigment and alpha (between Pov and Blender,
+ # alpha 0 and 1 are reversed)
+ file.write(
+ '\npigment{ color srgbf < %.3g, %.3g, %.3g, %.3g> }\n'
+ % (init_color[0], init_color[1], init_color[2], 1.0 - init_color[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 != total_number_of_strands:
+ file.write(',\n')
+ else:
+ file.write('\n')
+
+ # End the array declaration.
+
+ file.write('}\n')
+ file.write('\n')
+
+ if not textured_hair:
+ # 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' % total_number_of_strands)
+ file.write(' object {HairArray[I]')
+ if not textured_hair:
+ 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')
+
+ write_matrix(global_matrix @ ob.matrix_world)
+
+ file.write('}')
+ print('Totals hairstrands written: %i' % total_number_of_strands)
+ print('Number of tufts (particle systems)', len(ob.particle_systems))
+
+ # Set back the displayed number of particles to preview count
+ # p_sys.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,
+ # it's automatic now.
diff --git a/render_povray/primitives.py b/render_povray/object_primitives.py
index 6d864220..4556f2df 100644..100755
--- a/render_povray/primitives.py
+++ b/render_povray/object_primitives.py
@@ -19,13 +19,12 @@
# <pep8 compliant>
""" Get POV-Ray specific objects In and Out of Blender """
-
-import bpy
+from math import pi, cos, sin
import os.path
+import bpy
+from bpy_extras.object_utils import object_data_add
from bpy_extras.io_utils import ImportHelper
-from bpy_extras import object_utils
-from bpy.utils import register_class
-from math import atan, pi, degrees, sqrt, cos, sin
+from bpy.utils import register_class, unregister_class
from bpy.types import Operator
from bpy.props import (
@@ -35,8 +34,6 @@ from bpy.props import (
FloatProperty,
FloatVectorProperty,
EnumProperty,
- PointerProperty,
- CollectionProperty,
)
from mathutils import Vector, Matrix
@@ -45,6 +42,69 @@ from mathutils import Vector, Matrix
# import collections
+def write_object_modifiers(scene, 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
+ onceCSG = 0
+ for mod in ob.modifiers:
+ if onceCSG == 0:
+ if mod :
+ if mod.type == 'BOOLEAN':
+ if ob.pov.boolean_mod == "POV":
+ File.write("\tinside_vector <%.6g, %.6g, %.6g>\n" %
+ (ob.pov.inside_vector[0],
+ ob.pov.inside_vector[1],
+ ob.pov.inside_vector[2]))
+ onceCSG = 1
+ '''
+
+ 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 pov_define_mesh(mesh, verts, edges, faces, name, hide_geometry=True):
"""Generate proxy mesh."""
if mesh is None:
@@ -83,7 +143,9 @@ class POVRAY_OT_lathe_add(Operator):
ob_data.dimensions = '2D'
ob_data.transform(Matrix.Rotation(-pi / 2.0, 4, 'Z'))
ob.pov.object_as = 'LATHE'
- self.report({'INFO'}, "This native POV-Ray primitive")
+ self.report(
+ {'INFO'}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
+ )
ob.pov.curveshape = "lathe"
bpy.ops.object.modifier_add(type='SCREW')
mod = ob.modifiers[-1]
@@ -194,7 +256,7 @@ def pov_superellipsoid_define(context, op, ob):
mesh = pov_define_mesh(mesh, verts, [], faces, "SuperEllipsoid")
if not ob:
- ob = object_utils.object_data_add(context, mesh, operator=None)
+ ob = object_data_add(context, mesh, operator=None)
# engine = context.scene.render.engine what for?
ob = context.object
ob.name = ob.data.name = "PovSuperellipsoid"
@@ -222,29 +284,18 @@ class POVRAY_OT_superellipsoid_add(Operator):
bl_options = {'REGISTER', 'UNDO'}
COMPAT_ENGINES = {'POVRAY_RENDER'}
- # XXX Keep it in sync with __init__'s RenderPovSettingsConePrimitive
+ # Keep in sync within object_properties.py section Superellipsoid
+ # as this allows interactive update
# If someone knows how to define operators' props from a func, I'd be delighted to learn it!
- se_param1: FloatProperty(
- name="Parameter 1", description="", min=0.00, max=10.0, default=0.04
- )
+ se_param1: FloatProperty(name="Parameter 1", description="", min=0.00, max=10.0, default=0.04)
- se_param2: FloatProperty(
- name="Parameter 2", description="", min=0.00, max=10.0, default=0.04
- )
+ se_param2: FloatProperty(name="Parameter 2", description="", min=0.00, max=10.0, default=0.04)
se_u: IntProperty(
- name="U-segments",
- description="radial segmentation",
- default=20,
- min=4,
- max=265,
+ name="U-segments", description="radial segmentation", default=20, min=4, max=265
)
se_v: IntProperty(
- name="V-segments",
- description="lateral segmentation",
- default=20,
- min=4,
- max=265,
+ name="V-segments", description="lateral segmentation", default=20, min=4, max=265
)
se_n1: FloatProperty(
name="Ring manipulator",
@@ -261,11 +312,7 @@ class POVRAY_OT_superellipsoid_add(Operator):
max=100.0,
)
se_edit: EnumProperty(
- items=[
- ("NOTHING", "Nothing", ""),
- ("NGONS", "N-Gons", ""),
- ("TRIANGLES", "Triangles", ""),
- ],
+ items=[("NOTHING", "Nothing", ""), ("NGONS", "N-Gons", ""), ("TRIANGLES", "Triangles", "")],
name="Fill up and down",
description="",
default='TRIANGLES',
@@ -280,8 +327,7 @@ class POVRAY_OT_superellipsoid_add(Operator):
pov_superellipsoid_define(context, self, None)
self.report(
- {'INFO'},
- "This native POV-Ray primitive won't have any vertex to show in edit mode",
+ {'INFO'}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
)
return {'FINISHED'}
@@ -303,12 +349,7 @@ class POVRAY_OT_superellipsoid_update(Operator):
def poll(cls, context):
engine = context.scene.render.engine
ob = context.object
- return (
- ob
- and ob.data
- and ob.type == 'MESH'
- and engine in cls.COMPAT_ENGINES
- )
+ return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
def execute(self, context):
bpy.ops.object.mode_set(mode="EDIT")
@@ -322,60 +363,52 @@ class POVRAY_OT_superellipsoid_update(Operator):
return {'FINISHED'}
-def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
+def create_faces(vert_idx_1, vert_idx_2, closed=False, flipped=False):
+ """Generate viewport proxy mesh data for some pov primitives"""
faces = []
- if not vertIdx1 or not vertIdx2:
+ if not vert_idx_1 or not vert_idx_2:
return None
- if len(vertIdx1) < 2 and len(vertIdx2) < 2:
+ if len(vert_idx_1) < 2 and len(vert_idx_2) < 2:
return None
fan = False
- if len(vertIdx1) != len(vertIdx2):
- if len(vertIdx1) == 1 and len(vertIdx2) > 1:
+ if len(vert_idx_1) != len(vert_idx_2):
+ if len(vert_idx_1) == 1 and len(vert_idx_2) > 1:
fan = True
else:
return None
- total = len(vertIdx2)
+ total = len(vert_idx_2)
if closed:
if flipped:
- face = [vertIdx1[0], vertIdx2[0], vertIdx2[total - 1]]
+ face = [vert_idx_1[0], vert_idx_2[0], vert_idx_2[total - 1]]
if not fan:
- face.append(vertIdx1[total - 1])
+ face.append(vert_idx_1[total - 1])
faces.append(face)
else:
- face = [vertIdx2[0], vertIdx1[0]]
+ face = [vert_idx_2[0], vert_idx_1[0]]
if not fan:
- face.append(vertIdx1[total - 1])
- face.append(vertIdx2[total - 1])
+ face.append(vert_idx_1[total - 1])
+ face.append(vert_idx_2[total - 1])
faces.append(face)
for num in range(total - 1):
if flipped:
if fan:
- face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]]
+ face = [vert_idx_2[num], vert_idx_1[0], vert_idx_2[num + 1]]
else:
- face = [
- vertIdx2[num],
- vertIdx1[num],
- vertIdx1[num + 1],
- vertIdx2[num + 1],
- ]
+ face = [vert_idx_2[num], vert_idx_1[num], vert_idx_1[num + 1], vert_idx_2[num + 1]]
faces.append(face)
else:
if fan:
- face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]]
+ face = [vert_idx_1[0], vert_idx_2[num], vert_idx_2[num + 1]]
else:
- face = [
- vertIdx1[num],
- vertIdx2[num],
- vertIdx2[num + 1],
- vertIdx1[num + 1],
- ]
+ face = [vert_idx_1[num], vert_idx_2[num], vert_idx_2[num + 1], vert_idx_1[num + 1]]
faces.append(face)
return faces
def power(a, b):
+ """Workaround to negative a, where the math.pow() method would return a ValueError."""
if a < 0:
return -((-a) ** b)
return a ** b
@@ -392,22 +425,17 @@ def supertoroid(R, r, u, v, n1, n2):
for j in range(v):
c2 = R + r * power(cos(j * b), n2)
s2 = r * power(sin(j * b), n2)
- verts.append(
- (c * c2, s * c2, s2)
- ) # type as a (mathutils.Vector(c*c2,s*c2,s2))?
+ verts.append((c * c2, s * c2, s2)) # type as a (mathutils.Vector(c*c2,s*c2,s2))?
if i > 0:
- f = createFaces(
- range((i - 1) * v, i * v),
- range(i * v, (i + 1) * v),
- closed=True,
- )
+ f = create_faces(range((i - 1) * v, i * v), range(i * v, (i + 1) * v), closed=True)
faces.extend(f)
- f = createFaces(range((u - 1) * v, u * v), range(v), closed=True)
+ f = create_faces(range((u - 1) * v, u * v), range(v), closed=True)
faces.extend(f)
return verts, faces
def pov_supertorus_define(context, op, ob):
+ """Pick POV supertorus properties either from operator (object creation/import) or data updating """
if op:
mesh = None
st_R = op.st_R
@@ -444,7 +472,7 @@ def pov_supertorus_define(context, op, ob):
verts, faces = supertoroid(rad1, rad2, st_u, st_v, st_n1, st_n2)
mesh = pov_define_mesh(mesh, verts, [], faces, "PovSuperTorus", True)
if not ob:
- ob = object_utils.object_data_add(context, mesh, operator=None)
+ ob = object_data_add(context, mesh, operator=None)
ob.pov.object_as = 'SUPERTORUS'
ob.pov.st_major_radius = st_R
ob.pov.st_minor_radius = st_r
@@ -473,25 +501,13 @@ class POVRAY_OT_supertorus_add(Operator):
max=100.0,
)
st_r: FloatProperty(
- name="small radius",
- description="The radius of the tube",
- default=0.3,
- min=0.01,
- max=100.0,
+ name="small radius", description="The radius of the tube", default=0.3, min=0.01, max=100.0
)
st_u: IntProperty(
- name="U-segments",
- description="radial segmentation",
- default=16,
- min=3,
- max=265,
+ name="U-segments", description="radial segmentation", default=16, min=3, max=265
)
st_v: IntProperty(
- name="V-segments",
- description="lateral segmentation",
- default=8,
- min=3,
- max=265,
+ name="V-segments", description="lateral segmentation", default=8, min=3, max=265
)
st_n1: FloatProperty(
name="Ring manipulator",
@@ -508,13 +524,9 @@ class POVRAY_OT_supertorus_add(Operator):
max=100.0,
)
st_ie: BoolProperty(
- name="Use Int.+Ext. radii",
- description="Use internal and external radii",
- default=False,
- )
- st_edit: BoolProperty(
- name="", description="", default=False, options={'HIDDEN'}
+ name="Use Int.+Ext. radii", description="Use internal and external radii", default=False
)
+ st_edit: BoolProperty(name="", description="", default=False, options={'HIDDEN'})
@classmethod
def poll(cls, context):
@@ -525,8 +537,7 @@ class POVRAY_OT_supertorus_add(Operator):
pov_supertorus_define(context, self, None)
self.report(
- {'INFO'},
- "This native POV-Ray primitive won't have any vertex to show in edit mode",
+ {'INFO'}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
)
return {'FINISHED'}
@@ -547,12 +558,7 @@ class POVRAY_OT_supertorus_update(Operator):
def poll(cls, context):
engine = context.scene.render.engine
ob = context.object
- return (
- ob
- and ob.data
- and ob.type == 'MESH'
- and engine in cls.COMPAT_ENGINES
- )
+ return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
def execute(self, context):
bpy.ops.object.mode_set(mode="EDIT")
@@ -577,18 +583,12 @@ class POVRAY_OT_loft_add(Operator):
COMPAT_ENGINES = {'POVRAY_RENDER'}
loft_n: IntProperty(
- name="Segments",
- description="Vertical segments",
- default=16,
- min=3,
- max=720,
+ name="Segments", description="Vertical segments", default=16, min=3, max=720
)
loft_rings_bottom: IntProperty(
name="Bottom", description="Bottom rings", default=5, min=2, max=100
)
- loft_rings_side: IntProperty(
- name="Side", description="Side rings", default=10, min=2, max=100
- )
+ loft_rings_side: IntProperty(name="Side", description="Side rings", default=10, min=2, max=100)
loft_thick: FloatProperty(
name="Thickness",
description="Manipulates the shape of the Ring",
@@ -596,9 +596,7 @@ class POVRAY_OT_loft_add(Operator):
min=0.01,
max=1.0,
)
- loft_r: FloatProperty(
- name="Radius", description="Radius", default=1, min=0.01, max=10
- )
+ loft_r: FloatProperty(name="Radius", description="Radius", default=1, min=0.01, max=10)
loft_height: FloatProperty(
name="Height",
description="Manipulates the shape of the Ring",
@@ -610,10 +608,10 @@ class POVRAY_OT_loft_add(Operator):
def execute(self, context):
props = self.properties
- loftData = bpy.data.curves.new('Loft', type='CURVE')
- loftData.dimensions = '3D'
- loftData.resolution_u = 2
- # loftData.show_normal_face = False # deprecated in 2.8
+ loft_data = bpy.data.curves.new('Loft', type='CURVE')
+ loft_data.dimensions = '3D'
+ loft_data.resolution_u = 2
+ # loft_data.show_normal_face = False # deprecated in 2.8
n = props.loft_n
thick = props.loft_thick
side = props.loft_rings_side
@@ -633,11 +631,11 @@ class POVRAY_OT_loft_add(Operator):
coords.append((x, y, z))
angle += pi * 2 / n
r0 += distB
- nurbs = loftData.splines.new('NURBS')
+ nurbs = loft_data.splines.new('NURBS')
nurbs.points.add(len(coords) - 1)
- for i, coord in enumerate(coords):
+ for c, coord in enumerate(coords):
x, y, z = coord
- nurbs.points[i].co = (x, y, z, 1)
+ nurbs.points[c].co = (x, y, z, 1)
nurbs.use_cyclic_u = True
for i in range(side):
z += h / side
@@ -648,11 +646,11 @@ class POVRAY_OT_loft_add(Operator):
y = r * sin(angle)
coords.append((x, y, z))
angle += pi * 2 / n
- nurbs = loftData.splines.new('NURBS')
+ nurbs = loft_data.splines.new('NURBS')
nurbs.points.add(len(coords) - 1)
- for i, coord in enumerate(coords):
+ for c, coord in enumerate(coords):
x, y, z = coord
- nurbs.points[i].co = (x, y, z, 1)
+ nurbs.points[c].co = (x, y, z, 1)
nurbs.use_cyclic_u = True
r -= thick
for i in range(side):
@@ -663,11 +661,11 @@ class POVRAY_OT_loft_add(Operator):
y = r * sin(angle)
coords.append((x, y, z))
angle += pi * 2 / n
- nurbs = loftData.splines.new('NURBS')
+ nurbs = loft_data.splines.new('NURBS')
nurbs.points.add(len(coords) - 1)
- for i, coord in enumerate(coords):
+ for c, coord in enumerate(coords):
x, y, z = coord
- nurbs.points[i].co = (x, y, z, 1)
+ nurbs.points[c].co = (x, y, z, 1)
nurbs.use_cyclic_u = True
z -= h / side
z = (-h / 2) + thick
@@ -681,13 +679,13 @@ class POVRAY_OT_loft_add(Operator):
coords.append((x, y, z))
angle += pi * 2 / n
r -= distB
- nurbs = loftData.splines.new('NURBS')
+ nurbs = loft_data.splines.new('NURBS')
nurbs.points.add(len(coords) - 1)
- for i, coord in enumerate(coords):
+ for c, coord in enumerate(coords):
x, y, z = coord
- nurbs.points[i].co = (x, y, z, 1)
+ nurbs.points[c].co = (x, y, z, 1)
nurbs.use_cyclic_u = True
- ob = bpy.data.objects.new('Loft_shape', loftData)
+ ob = bpy.data.objects.new('Loft_shape', loft_data)
scn = bpy.context.scene
scn.collection.objects.link(ob)
context.view_layer.objects.active = ob
@@ -715,9 +713,7 @@ class POVRAY_OT_plane_add(Operator):
ob.name = ob.data.name = 'PovInfinitePlane'
bpy.ops.object.mode_set(mode="EDIT")
self.report(
- {'INFO'},
- "This native POV-Ray primitive "
- "won't have any vertex to show in edit mode",
+ {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
)
bpy.ops.mesh.hide(unselected=False)
bpy.ops.object.mode_set(mode="OBJECT")
@@ -745,9 +741,7 @@ class POVRAY_OT_box_add(Operator):
ob.name = ob.data.name = 'PovBox'
bpy.ops.object.mode_set(mode="EDIT")
self.report(
- {'INFO'},
- "This native POV-Ray primitive "
- "won't have any vertex to show in edit mode",
+ {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
)
bpy.ops.mesh.hide(unselected=False)
bpy.ops.object.mode_set(mode="OBJECT")
@@ -756,6 +750,7 @@ class POVRAY_OT_box_add(Operator):
def pov_cylinder_define(context, op, ob, radius, loc, loc_cap):
+ """Pick POV cylinder properties either from creation operator, import, or data update """
if op:
R = op.R
loc = bpy.context.scene.cursor.location
@@ -784,11 +779,7 @@ def pov_cylinder_define(context, op, ob, radius, loc, loc_cap):
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.delete(type='VERT')
bpy.ops.mesh.primitive_cylinder_add(
- radius=radius,
- depth=depth,
- location=loc,
- rotation=roteuler,
- end_fill_type='NGON',
+ radius=radius, depth=depth, location=loc, rotation=roteuler, end_fill_type='NGON'
) #'NOTHING'
bpy.ops.transform.translate(value=trans)
@@ -807,7 +798,8 @@ class POVRAY_OT_cylinder_add(Operator):
bl_description = "Add Cylinder"
bl_options = {'REGISTER', 'UNDO'}
- # XXX Keep it in sync with __init__'s cylinder Primitive
+ # Keep in sync within object_properties.py section Cylinder
+ # as this allows interactive update
R: FloatProperty(name="Cylinder radius", min=0.00, max=10.0, default=1.0)
imported_cyl_loc: FloatVectorProperty(
@@ -838,8 +830,7 @@ class POVRAY_OT_cylinder_add(Operator):
LOC_CAP = props.imported_cyl_loc_cap
self.report(
{'INFO'},
- "This native POV-Ray primitive "
- "won't have any vertex to show in edit mode",
+ "This native POV-Ray primitive " "won't have any vertex to show in edit mode",
)
pov_cylinder_define(context, self, None, self.R, LOC, LOC_CAP)
@@ -906,10 +897,7 @@ def pov_sphere_define(context, op, ob, loc):
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.delete(type='VERT')
bpy.ops.mesh.primitive_ico_sphere_add(
- subdivisions=4,
- radius=ob.pov.sphere_radius,
- location=loc,
- rotation=obrot,
+ subdivisions=4, radius=ob.pov.sphere_radius, location=loc, rotation=obrot
)
# bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
bpy.ops.transform.resize(value=obscale)
@@ -921,9 +909,7 @@ def pov_sphere_define(context, op, ob, loc):
# bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
if not ob:
- bpy.ops.mesh.primitive_ico_sphere_add(
- subdivisions=4, radius=R, location=loc
- )
+ bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, radius=R, location=loc)
ob = context.object
ob.name = ob.data.name = "PovSphere"
ob.pov.object_as = "SPHERE"
@@ -943,7 +929,8 @@ class POVRAY_OT_sphere_add(Operator):
bl_description = "Add Sphere Shape"
bl_options = {'REGISTER', 'UNDO'}
- # XXX Keep it in sync with __init__'s torus Primitive
+ # Keep in sync within object_properties.py section Sphere
+ # as this allows interactive update
R: FloatProperty(name="Sphere radius", min=0.00, max=10.0, default=0.5)
imported_loc: FloatVectorProperty(
@@ -966,8 +953,7 @@ class POVRAY_OT_sphere_add(Operator):
LOC = props.imported_loc
self.report(
{'INFO'},
- "This native POV-Ray primitive "
- "won't have any vertex to show in edit mode",
+ "This native POV-Ray primitive " "won't have any vertex to show in edit mode",
)
pov_sphere_define(context, self, None, LOC)
@@ -1006,18 +992,11 @@ class POVRAY_OT_sphere_update(Operator):
def poll(cls, context):
engine = context.scene.render.engine
ob = context.object
- return (
- ob
- and ob.data
- and ob.type == 'MESH'
- and engine in cls.COMPAT_ENGINES
- )
+ return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
def execute(self, context):
- pov_sphere_define(
- context, None, context.object, context.object.location
- )
+ pov_sphere_define(context, None, context.object, context.object.location)
return {'FINISHED'}
@@ -1076,7 +1055,7 @@ def pov_cone_define(context, op, ob):
mesh = pov_define_mesh(mesh, verts, [], faces, "PovCone", True)
if not ob:
- ob = object_utils.object_data_add(context, mesh, operator=None)
+ ob = object_data_add(context, mesh, operator=None)
ob.pov.object_as = "CONE"
ob.pov.cone_base_radius = base
ob.pov.cone_cap_radius = cap
@@ -1094,7 +1073,7 @@ class POVRAY_OT_cone_add(Operator):
bl_options = {'REGISTER', 'UNDO'}
COMPAT_ENGINES = {'POVRAY_RENDER'}
- # XXX Keep it in sync with __init__.py's RenderPovSettingsConePrimitive
+ # Keep in sync within object_properties.py section Cone
# If someone knows how to define operators' props from a func, I'd be delighted to learn it!
base: FloatProperty(
name="Base radius",
@@ -1118,11 +1097,7 @@ class POVRAY_OT_cone_add(Operator):
max=265,
)
height: FloatProperty(
- name="Height",
- description="Height of the cone",
- default=2.0,
- min=0.01,
- max=100.0,
+ name="Height", description="Height of the cone", default=2.0, min=0.01, max=100.0
)
@classmethod
@@ -1134,8 +1109,7 @@ class POVRAY_OT_cone_add(Operator):
pov_cone_define(context, self, None)
self.report(
- {'INFO'},
- "This native POV-Ray primitive won't have any vertex to show in edit mode",
+ {'INFO'}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
)
return {'FINISHED'}
@@ -1156,12 +1130,7 @@ class POVRAY_OT_cone_update(Operator):
def poll(cls, context):
engine = context.scene.render.engine
ob = context.object
- return (
- ob
- and ob.data
- and ob.type == 'MESH'
- and engine in cls.COMPAT_ENGINES
- )
+ return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
def execute(self, context):
bpy.ops.object.mode_set(mode="EDIT")
@@ -1196,9 +1165,7 @@ class POVRAY_OT_isosurface_box_add(Operator):
ob = context.object
bpy.ops.object.mode_set(mode="EDIT")
self.report(
- {'INFO'},
- "This native POV-Ray primitive "
- "won't have any vertex to show in edit mode",
+ {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
)
bpy.ops.mesh.hide(unselected=False)
bpy.ops.object.mode_set(mode="OBJECT")
@@ -1226,9 +1193,7 @@ class POVRAY_OT_isosurface_sphere_add(Operator):
ob = context.object
bpy.ops.object.mode_set(mode="EDIT")
self.report(
- {'INFO'},
- "This native POV-Ray primitive "
- "won't have any vertex to show in edit mode",
+ {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
)
bpy.ops.mesh.hide(unselected=False)
bpy.ops.object.mode_set(mode="OBJECT")
@@ -1338,39 +1303,29 @@ class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
bl_description = "Add Height Field"
bl_options = {'REGISTER', 'UNDO'}
- # XXX Keep it in sync with __init__'s hf Primitive
+ # Keep in sync within object_properties.py section HeightFields
+ # as this allows interactive update
+
# filename_ext = ".png"
# filter_glob = StringProperty(
# default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
# options={'HIDDEN'},
# )
- quality: IntProperty(
- name="Quality", description="", default=100, min=1, max=100
- )
+ quality: IntProperty(name="Quality", description="", default=100, min=1, max=100)
hf_filename: StringProperty(maxlen=1024)
- hf_gamma: FloatProperty(
- name="Gamma", description="Gamma", min=0.0001, max=20.0, default=1.0
- )
+ hf_gamma: FloatProperty(name="Gamma", description="Gamma", min=0.0001, max=20.0, default=1.0)
- hf_premultiplied: BoolProperty(
- name="Premultiplied", description="Premultiplied", default=True
- )
+ hf_premultiplied: BoolProperty(name="Premultiplied", description="Premultiplied", default=True)
hf_smooth: BoolProperty(name="Smooth", description="Smooth", default=False)
hf_water: FloatProperty(
- name="Water Level",
- description="Wather Level",
- min=0.00,
- max=1.00,
- default=0.0,
+ name="Water Level", description="Wather Level", min=0.00, max=1.00, default=0.0
)
- hf_hierarchy: BoolProperty(
- name="Hierarchy", description="Height field hierarchy", default=True
- )
+ hf_hierarchy: BoolProperty(name="Hierarchy", description="Height field hierarchy", default=True)
def execute(self, context):
props = self.properties
@@ -1390,9 +1345,7 @@ class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
w, h = hf_tex.image.size[:]
w = int(w / res)
h = int(h / res)
- bpy.ops.mesh.primitive_grid_add(
- x_subdivisions=w, y_subdivisions=h, size=0.5
- )
+ bpy.ops.mesh.primitive_grid_add(x_subdivisions=w, y_subdivisions=h, size=0.5)
ob = context.object
ob.name = ob.data.name = '%s' % im_name
ob.data.materials.append(mat)
@@ -1409,7 +1362,9 @@ class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
bpy.ops.mesh.hide(unselected=False)
bpy.ops.object.mode_set(mode="OBJECT")
ob.pov.object_as = 'HEIGHT_FIELD'
- ob.pov.hf_filename = impath
+ # POV-Ray will soon use only forwards slashes on every OS and already can
+ forward_impath = impath.replace(os.sep, '/')
+ ob.pov.hf_filename = forward_impath
return {'FINISHED'}
@@ -1417,6 +1372,7 @@ class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
def pov_torus_define(context, op, ob):
"""Add the representation of POV torus using just a Blender torus.
+ Picking properties either from creation operator, import, or data update.
But flag its primitive type with a specific pov.object_as attribute and lock edit mode
to keep proxy consistency by hiding edit geometry."""
@@ -1454,10 +1410,7 @@ def pov_torus_define(context, op, ob):
if not ob:
bpy.ops.mesh.primitive_torus_add(
- major_segments=mas,
- minor_segments=mis,
- major_radius=mar,
- minor_radius=mir,
+ major_segments=mas, minor_segments=mis, major_radius=mar, minor_radius=mir
)
ob = context.object
ob.name = ob.data.name = "PovTorus"
@@ -1479,13 +1432,10 @@ class POVRAY_OT_torus_add(Operator):
bl_description = "Add Torus"
bl_options = {'REGISTER', 'UNDO'}
- # XXX Keep it in sync with __init__'s torus Primitive
- mas: IntProperty(
- name="Major Segments", description="", default=48, min=3, max=720
- )
- mis: IntProperty(
- name="Minor Segments", description="", default=12, min=3, max=720
- )
+ # Keep in sync within object_properties.py section Torus
+ # as this allows interactive update
+ mas: IntProperty(name="Major Segments", description="", default=48, min=3, max=720)
+ mis: IntProperty(name="Minor Segments", description="", default=12, min=3, max=720)
mar: FloatProperty(name="Major Radius", description="", default=1.0)
mir: FloatProperty(name="Minor Radius", description="", default=0.25)
@@ -1497,9 +1447,7 @@ class POVRAY_OT_torus_add(Operator):
mis = props.mis
pov_torus_define(context, self, None)
self.report(
- {'INFO'},
- "This native POV-Ray primitive "
- "won't have any vertex to show in edit mode",
+ {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
)
return {'FINISHED'}
@@ -1520,12 +1468,7 @@ class POVRAY_OT_torus_update(Operator):
def poll(cls, context):
engine = context.scene.render.engine
ob = context.object
- return (
- ob
- and ob.data
- and ob.type == 'MESH'
- and engine in cls.COMPAT_ENGINES
- )
+ return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
def execute(self, context):
@@ -1545,19 +1488,17 @@ class POVRAY_OT_prism_add(Operator):
bl_description = "Create Prism"
bl_options = {'REGISTER', 'UNDO'}
- prism_n: IntProperty(
- name="Sides", description="Number of sides", default=5, min=3, max=720
- )
+ prism_n: IntProperty(name="Sides", description="Number of sides", default=5, min=3, max=720)
prism_r: FloatProperty(name="Radius", description="Radius", default=1.0)
def execute(self, context):
props = self.properties
- loftData = bpy.data.curves.new('Prism', type='CURVE')
- loftData.dimensions = '2D'
- loftData.resolution_u = 2
- # loftData.show_normal_face = False
- loftData.extrude = 2
+ loft_data = bpy.data.curves.new('Prism', type='CURVE')
+ loft_data.dimensions = '2D'
+ loft_data.resolution_u = 2
+ # loft_data.show_normal_face = False
+ loft_data.extrude = 2
n = props.prism_n
r = props.prism_r
coords = []
@@ -1568,14 +1509,14 @@ class POVRAY_OT_prism_add(Operator):
y = r * sin(angle)
coords.append((x, y, z))
angle += pi * 2 / n
- poly = loftData.splines.new('POLY')
+ poly = loft_data.splines.new('POLY')
poly.points.add(len(coords) - 1)
for i, coord in enumerate(coords):
x, y, z = coord
poly.points[i].co = (x, y, z, 1)
poly.use_cyclic_u = True
- ob = bpy.data.objects.new('Prism_shape', loftData)
+ ob = bpy.data.objects.new('Prism_shape', loft_data)
scn = bpy.context.scene
scn.collection.objects.link(ob)
context.view_layer.objects.active = ob
@@ -1587,8 +1528,11 @@ class POVRAY_OT_prism_add(Operator):
##############################PARAMETRIC######################################
def pov_parametric_define(context, op, ob):
- """Add the representation of POV parametric surfaces by math surface from add mesh extra objects addon."""
+ """Add the representation of POV parametric surfaces by math surface from add mesh extra objects addon.
+ Picking properties either from creation operator, import, or data update.
+ But flag its primitive type with a specific pov.object_as attribute and lock edit mode
+ to keep proxy consistency by hiding edit geometry."""
if op:
u_min = op.u_min
u_max = op.u_max
@@ -1631,7 +1575,10 @@ def pov_parametric_define(context, op, ob):
bpy.ops.mesh.select_all(action='SELECT')
# extra work:
bpy.ops.transform.translate(value=(obloc - curloc), proportional_size=1)
- bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
+ # XXX TODO : https://devtalk.blender.org/t/bpy-ops-transform-rotate-option-axis/6235/7
+ # to complete necessary extra work rotation, after updating from blender version > 2.92
+ # update and uncomment below, but simple axis deprecated since 2.8
+ # bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
bpy.ops.mesh.hide(unselected=False)
bpy.ops.object.mode_set(mode="OBJECT")
@@ -1671,7 +1618,8 @@ class POVRAY_OT_parametric_add(Operator):
bl_description = "Add Paramertic"
bl_options = {'REGISTER', 'UNDO'}
- # XXX Keep it in sync with __init__'s Parametric primitive
+ # Keep in sync within object_properties.py section Parametric primitive
+ # as this allows interactive update
u_min: FloatProperty(name="U Min", description="", default=0.0)
v_min: FloatProperty(name="V Min", description="", default=0.0)
u_max: FloatProperty(name="U Max", description="", default=6.28)
@@ -1692,9 +1640,7 @@ class POVRAY_OT_parametric_add(Operator):
pov_parametric_define(context, self, None)
self.report(
- {'INFO'},
- "This native POV-Ray primitive "
- "won't have any vertex to show in edit mode",
+ {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
)
return {'FINISHED'}
@@ -1715,12 +1661,7 @@ class POVRAY_OT_parametric_update(Operator):
def poll(cls, context):
engine = context.scene.render.engine
ob = context.object
- return (
- ob
- and ob.data
- and ob.type == 'MESH'
- and engine in cls.COMPAT_ENGINES
- )
+ return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
def execute(self, context):
@@ -1741,19 +1682,14 @@ class POVRAY_OT_shape_polygon_to_circle_add(Operator):
bl_options = {'REGISTER', 'UNDO'}
COMPAT_ENGINES = {'POVRAY_RENDER'}
- # XXX Keep it in sync with __init__'s polytocircle properties
+ # Keep in sync within object_properties.py section PolygonToCircle properties
+ # as this allows interactive update
polytocircle_resolution: IntProperty(
name="Resolution", description="", default=3, min=0, max=256
)
- polytocircle_ngon: IntProperty(
- name="NGon", description="", min=3, max=64, default=5
- )
- polytocircle_ngonR: FloatProperty(
- name="NGon Radius", description="", default=0.3
- )
- polytocircle_circleR: FloatProperty(
- name="Circle Radius", description="", default=1.0
- )
+ polytocircle_ngon: IntProperty(name="NGon", description="", min=3, max=64, default=5)
+ polytocircle_ngonR: FloatProperty(name="NGon Radius", description="", default=0.3)
+ polytocircle_circleR: FloatProperty(name="Circle Radius", description="", default=1.0)
def execute(self, context):
props = self.properties
@@ -1771,10 +1707,7 @@ class POVRAY_OT_shape_polygon_to_circle_add(Operator):
numCircleVerts = ngon + (ngon * resolution)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.primitive_circle_add(
- vertices=numCircleVerts,
- radius=circleR,
- fill_type='NGON',
- enter_editmode=True,
+ vertices=numCircleVerts, radius=circleR, fill_type='NGON', enter_editmode=True
)
bpy.ops.transform.translate(value=(0, 0, -1))
bpy.ops.mesh.select_all(action='SELECT')
@@ -1782,10 +1715,7 @@ class POVRAY_OT_shape_polygon_to_circle_add(Operator):
if ngon < 5:
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.primitive_circle_add(
- vertices=ngon,
- radius=ngonR,
- fill_type='TRIFAN',
- enter_editmode=True,
+ vertices=ngon, radius=ngonR, fill_type='TRIFAN', enter_editmode=True
)
bpy.ops.transform.translate(value=(0, 0, 1))
bpy.ops.mesh.select_all(action='SELECT')
@@ -1803,547 +1733,6 @@ class POVRAY_OT_shape_polygon_to_circle_add(Operator):
return {'FINISHED'}
-#############################IMPORT
-
-
-class ImportPOV(bpy.types.Operator, ImportHelper):
- """Load Povray files"""
-
- bl_idname = "import_scene.pov"
- bl_label = "POV-Ray files (.pov/.inc)"
- bl_options = {'PRESET', 'UNDO'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- # -----------
- # File props.
- files: CollectionProperty(
- type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'}
- )
- directory: StringProperty(
- maxlen=1024, subtype='FILE_PATH', options={'HIDDEN', 'SKIP_SAVE'}
- )
-
- filename_ext = {".pov", ".inc"}
- filter_glob: StringProperty(default="*.pov;*.inc", options={'HIDDEN'})
-
- import_at_cur: BoolProperty(
- name="Import at Cursor Location",
- description="Ignore Object Matrix",
- default=False,
- )
-
- def execute(self, context):
- from mathutils import Matrix
-
- verts = []
- faces = []
- materials = []
- blendMats = [] ##############
- povMats = [] ##############
- colors = []
- matNames = []
- lenverts = None
- lenfaces = None
- suffix = -1
- name = 'Mesh2_%s' % suffix
- name_search = False
- verts_search = False
- faces_search = False
- plane_search = False
- box_search = False
- cylinder_search = False
- sphere_search = False
- cone_search = False
- tex_search = False ##################
- cache = []
- matrixes = {}
- writematrix = False
- index = None
- value = None
- # filepov = bpy.path.abspath(self.filepath) #was used for single files
-
- def mat_search(cache):
- r = g = b = 0.5
- f = t = 0
- color = None
-
- for item, value in enumerate(cache):
-
- if value == 'texture':
- pass
-
- if value == 'pigment':
-
- if cache[item + 2] in {'rgb', 'srgb'}:
- pass
-
- elif cache[item + 2] in {'rgbf', 'srgbf'}:
- pass
-
- elif cache[item + 2] in {'rgbt', 'srgbt'}:
- try:
- r, g, b, t = (
- float(cache[item + 3]),
- float(cache[item + 4]),
- float(cache[item + 5]),
- float(cache[item + 6]),
- )
- except:
- r = g = b = t = float(cache[item + 2])
- color = (r, g, b, t)
-
- elif cache[item + 2] in {'rgbft', 'srgbft'}:
- pass
-
- else:
- pass
-
- if colors == [] or (colors != [] and color not in colors):
- colors.append(color)
- name = ob.name + "_mat"
- matNames.append(name)
- mat = bpy.data.materials.new(name)
- mat.diffuse_color = (r, g, b)
- mat.alpha = 1 - t
- if mat.alpha != 1:
- mat.use_transparency = True
- ob.data.materials.append(mat)
-
- else:
- for i, value in enumerate(colors):
- if color == value:
- ob.data.materials.append(
- bpy.data.materials[matNames[i]]
- )
-
- for file in self.files:
- print("Importing file: " + file.name)
- filepov = self.directory + file.name
- for line in open(filepov):
- string = line.replace("{", " ")
- string = string.replace("}", " ")
- string = string.replace("<", " ")
- string = string.replace(">", " ")
- string = string.replace(",", " ")
- lw = string.split()
- lenwords = len(lw)
- if lw:
- if lw[0] == "object":
- writematrix = True
- if writematrix:
- if lw[0] not in {"object", "matrix"}:
- index = lw[0]
- if lw[0] in {"matrix"}:
- value = [
- float(lw[1]),
- float(lw[2]),
- float(lw[3]),
- float(lw[4]),
- float(lw[5]),
- float(lw[6]),
- float(lw[7]),
- float(lw[8]),
- float(lw[9]),
- float(lw[10]),
- float(lw[11]),
- float(lw[12]),
- ]
- matrixes[index] = value
- writematrix = False
- for line in open(filepov):
- S = line.replace("{", " { ")
- S = S.replace("}", " } ")
- S = S.replace(",", " ")
- S = S.replace("<", "")
- S = S.replace(">", " ")
- S = S.replace("=", " = ")
- S = S.replace(";", " ; ")
- S = S.split()
- lenS = len(S)
- for i, word in enumerate(S):
- ##################Primitives Import##################
- if word == 'cone':
- cone_search = True
- name_search = False
- if cone_search:
- cache.append(word)
- if cache[-1] == '}':
- try:
- x0 = float(cache[2])
- y0 = float(cache[3])
- z0 = float(cache[4])
- r0 = float(cache[5])
- x1 = float(cache[6])
- y1 = float(cache[7])
- z1 = float(cache[8])
- r1 = float(cache[9])
- # Y is height in most pov files, not z
- bpy.ops.pov.cone_add(
- base=r0, cap=r1, height=(y1 - y0)
- )
- ob = context.object
- ob.location = (x0, y0, z0)
- # ob.scale = (r,r,r)
- mat_search(cache)
- except (ValueError):
- pass
- cache = []
- cone_search = False
- if word == 'plane':
- plane_search = True
- name_search = False
- if plane_search:
- cache.append(word)
- if cache[-1] == '}':
- try:
- bpy.ops.pov.addplane()
- ob = context.object
- mat_search(cache)
- except (ValueError):
- pass
- cache = []
- plane_search = False
- if word == 'box':
- box_search = True
- name_search = False
- if box_search:
- cache.append(word)
- if cache[-1] == '}':
- try:
- x0 = float(cache[2])
- y0 = float(cache[3])
- z0 = float(cache[4])
- x1 = float(cache[5])
- y1 = float(cache[6])
- z1 = float(cache[7])
- # imported_corner_1=(x0, y0, z0)
- # imported_corner_2 =(x1, y1, z1)
- center = (
- (x0 + x1) / 2,
- (y0 + y1) / 2,
- (z0 + z1) / 2,
- )
- bpy.ops.pov.addbox()
- ob = context.object
- ob.location = center
- mat_search(cache)
-
- except (ValueError):
- pass
- cache = []
- box_search = False
- if word == 'cylinder':
- cylinder_search = True
- name_search = False
- if cylinder_search:
- cache.append(word)
- if cache[-1] == '}':
- try:
- x0 = float(cache[2])
- y0 = float(cache[3])
- z0 = float(cache[4])
- x1 = float(cache[5])
- y1 = float(cache[6])
- z1 = float(cache[7])
- imported_cyl_loc = (x0, y0, z0)
- imported_cyl_loc_cap = (x1, y1, z1)
-
- r = float(cache[8])
-
- vec = Vector(imported_cyl_loc_cap) - Vector(
- imported_cyl_loc
- )
- depth = vec.length
- rot = Vector((0, 0, 1)).rotation_difference(
- vec
- ) # Rotation from Z axis.
- trans = rot @ Vector(
- (0, 0, depth / 2)
- ) # Such that origin is at center of the base of the cylinder.
- # center = ((x0 + x1)/2,(y0 + y1)/2,(z0 + z1)/2)
- scaleZ = (
- sqrt(
- (x1 - x0) ** 2
- + (y1 - y0) ** 2
- + (z1 - z0) ** 2
- )
- / 2
- )
- bpy.ops.pov.addcylinder(
- R=r,
- imported_cyl_loc=imported_cyl_loc,
- imported_cyl_loc_cap=imported_cyl_loc_cap,
- )
- ob = context.object
- ob.location = (x0, y0, z0)
- ob.rotation_euler = rot.to_euler()
- ob.scale = (1, 1, scaleZ)
-
- # scale data rather than obj?
- # bpy.ops.object.mode_set(mode='EDIT')
- # bpy.ops.mesh.reveal()
- # bpy.ops.mesh.select_all(action='SELECT')
- # bpy.ops.transform.resize(value=(1,1,scaleZ), orient_type='LOCAL')
- # bpy.ops.mesh.hide(unselected=False)
- # bpy.ops.object.mode_set(mode='OBJECT')
-
- mat_search(cache)
-
- except (ValueError):
- pass
- cache = []
- cylinder_search = False
- if word == 'sphere':
- sphere_search = True
- name_search = False
- if sphere_search:
- cache.append(word)
- if cache[-1] == '}':
- x = y = z = r = 0
- try:
- x = float(cache[2])
- y = float(cache[3])
- z = float(cache[4])
- r = float(cache[5])
-
- except (ValueError):
- pass
- except:
- x = y = z = float(cache[2])
- r = float(cache[3])
- bpy.ops.pov.addsphere(R=r, imported_loc=(x, y, z))
- ob = context.object
- ob.location = (x, y, z)
- ob.scale = (r, r, r)
- mat_search(cache)
- cache = []
- sphere_search = False
- ##################End Primitives Import##################
- if word == '#declare':
- name_search = True
- if name_search:
- cache.append(word)
- if word == 'mesh2':
- name_search = False
- if cache[-2] == '=':
- name = cache[-3]
- else:
- suffix += 1
- cache = []
- if word in {'texture', ';'}:
- name_search = False
- cache = []
- if word == 'vertex_vectors':
- verts_search = True
- if verts_search:
- cache.append(word)
- if word == '}':
- verts_search = False
- lenverts = cache[2]
- cache.pop()
- cache.pop(0)
- cache.pop(0)
- cache.pop(0)
- for i in range(int(lenverts)):
- x = i * 3
- y = (i * 3) + 1
- z = (i * 3) + 2
- verts.append(
- (
- float(cache[x]),
- float(cache[y]),
- float(cache[z]),
- )
- )
- cache = []
- # if word == 'face_indices':
- # faces_search = True
- if word == 'texture_list': ########
- tex_search = True #######
- if tex_search: #########
- if (
- word
- not in {
- 'texture_list',
- 'texture',
- '{',
- '}',
- 'face_indices',
- }
- and word.isdigit() == False
- ): ##############
- povMats.append(word) #################
- if word == 'face_indices':
- tex_search = False ################
- faces_search = True
- if faces_search:
- cache.append(word)
- if word == '}':
- faces_search = False
- lenfaces = cache[2]
- cache.pop()
- cache.pop(0)
- cache.pop(0)
- cache.pop(0)
- lf = int(lenfaces)
- var = int(len(cache) / lf)
- for i in range(lf):
- if var == 3:
- v0 = i * 3
- v1 = i * 3 + 1
- v2 = i * 3 + 2
- faces.append(
- (
- int(cache[v0]),
- int(cache[v1]),
- int(cache[v2]),
- )
- )
- if var == 4:
- v0 = i * 4
- v1 = i * 4 + 1
- v2 = i * 4 + 2
- m = i * 4 + 3
- materials.append((int(cache[m])))
- faces.append(
- (
- int(cache[v0]),
- int(cache[v1]),
- int(cache[v2]),
- )
- )
- if var == 6:
- v0 = i * 6
- v1 = i * 6 + 1
- v2 = i * 6 + 2
- m0 = i * 6 + 3
- m1 = i * 6 + 4
- m2 = i * 6 + 5
- materials.append(
- (
- int(cache[m0]),
- int(cache[m1]),
- int(cache[m2]),
- )
- )
- faces.append(
- (
- int(cache[v0]),
- int(cache[v1]),
- int(cache[v2]),
- )
- )
- # mesh = pov_define_mesh(None, verts, [], faces, name, hide_geometry=False)
- # ob = object_utils.object_data_add(context, mesh, operator=None)
-
- me = bpy.data.meshes.new(name) ########
- ob = bpy.data.objects.new(name, me) ##########
- bpy.context.collection.objects.link(ob) #########
- me.from_pydata(verts, [], faces) ############
-
- for mat in bpy.data.materials: ##############
- blendMats.append(mat.name) #############
- for mName in povMats: #####################
- if mName not in blendMats: ###########
- povMat = bpy.data.materials.new(
- mName
- ) #################
- mat_search(cache)
- ob.data.materials.append(
- bpy.data.materials[mName]
- ) ###################
- if materials: ##################
- for i, val in enumerate(
- materials
- ): ####################
- try: ###################
- ob.data.polygons[
- i
- ].material_index = (
- val
- ) ####################
- except TypeError: ###################
- ob.data.polygons[
- i
- ].material_index = int(
- val[0]
- ) ##################
-
- blendMats = [] #########################
- povMats = [] #########################
- materials = [] #########################
- cache = []
- name_search = True
- if name in matrixes and self.import_at_cur == False:
- global_matrix = Matrix.Rotation(
- pi / 2.0, 4, 'X'
- )
- ob = bpy.context.object
- matrix = ob.matrix_world
- v = matrixes[name]
- matrix[0][0] = v[0]
- matrix[1][0] = v[1]
- matrix[2][0] = v[2]
- matrix[0][1] = v[3]
- matrix[1][1] = v[4]
- matrix[2][1] = v[5]
- matrix[0][2] = v[6]
- matrix[1][2] = v[7]
- matrix[2][2] = v[8]
- matrix[0][3] = v[9]
- matrix[1][3] = v[10]
- matrix[2][3] = v[11]
- matrix = global_matrix * ob.matrix_world
- ob.matrix_world = matrix
- verts = []
- faces = []
-
- # if word == 'pigment':
- # try:
- # #all indices have been incremented once to fit a bad test file
- # r,g,b,t = float(S[2]),float(S[3]),float(S[4]),float(S[5])
- # color = (r,g,b,t)
-
- # except (IndexError):
- # #all indices have been incremented once to fit alternate test file
- # r,g,b,t = float(S[3]),float(S[4]),float(S[5]),float(S[6])
- # color = (r,g,b,t)
- # except UnboundLocalError:
- # # In case no transmit is specified ? put it to 0
- # r,g,b,t = float(S[2]),float(S[3]),float(S[4],0)
- # color = (r,g,b,t)
-
- # except (ValueError):
- # color = (0.8,0.8,0.8,0)
- # pass
-
- # if colors == [] or (colors != [] and color not in colors):
- # colors.append(color)
- # name = ob.name+"_mat"
- # matNames.append(name)
- # mat = bpy.data.materials.new(name)
- # mat.diffuse_color = (r,g,b)
- # mat.alpha = 1-t
- # if mat.alpha != 1:
- # mat.use_transparency=True
- # ob.data.materials.append(mat)
- # print (colors)
- # else:
- # for i in range(len(colors)):
- # if color == colors[i]:
- # ob.data.materials.append(bpy.data.materials[matNames[i]])
-
- ##To keep Avogadro Camera angle:
- # for obj in bpy.context.view_layer.objects:
- # if obj.type == "CAMERA":
- # track = obj.constraints.new(type = "TRACK_TO")
- # track.target = ob
- # track.track_axis ="TRACK_NEGATIVE_Z"
- # track.up_axis = "UP_Y"
- # obj.location = (0,0,0)
- return {'FINISHED'}
-
-
classes = (
POVRAY_OT_lathe_add,
POVRAY_OT_superellipsoid_add,
@@ -2371,19 +1760,14 @@ classes = (
POVRAY_OT_parametric_add,
POVRAY_OT_parametric_update,
POVRAY_OT_shape_polygon_to_circle_add,
- ImportPOV,
)
def register():
- # from bpy.utils import register_class
-
for cls in classes:
register_class(cls)
def unregister():
- from bpy.utils import unregister_class
-
for cls in classes:
unregister_class(cls)
diff --git a/render_povray/object_properties.py b/render_povray/object_properties.py
new file mode 100755
index 00000000..8cea49af
--- /dev/null
+++ b/render_povray/object_properties.py
@@ -0,0 +1,670 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare object level properties controllable in UI and translated to POV"""
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+ BoolProperty,
+ IntProperty,
+ FloatProperty,
+ FloatVectorProperty,
+ StringProperty,
+ EnumProperty,
+ PointerProperty,
+)
+
+
+###############################################################################
+# Object POV properties.
+###############################################################################
+
+
+class RenderPovSettingsObject(PropertyGroup):
+ """Declare object and primitives level properties controllable in UI and translated to POV."""
+
+ # Pov inside_vector used for CSG
+ inside_vector: FloatVectorProperty(
+ name="CSG Inside Vector",
+ description="Direction to shoot CSG inside test rays at",
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(0.001, 0.001, 0.5),
+ options={"ANIMATABLE"},
+ subtype="XYZ",
+ )
+
+ # Importance sampling
+ importance_value: FloatProperty(
+ name="Radiosity Importance",
+ description="Priority value relative to other objects for sampling radiosity rays. "
+ "Increase to get more radiosity rays at comparatively small yet "
+ "bright objects",
+ min=0.01,
+ max=1.00,
+ default=0.50,
+ )
+
+ # Collect photons
+ collect_photons: BoolProperty(
+ name="Receive Photon Caustics",
+ description="Enable object to collect photons from other objects caustics. Turn "
+ "off for objects that don't really need to receive caustics (e.g. objects"
+ " that generate caustics often don't need to show any on themselves)",
+ default=True,
+ )
+
+ # Photons spacing_multiplier
+ spacing_multiplier: FloatProperty(
+ name="Photons Spacing Multiplier",
+ description="Multiplier value relative to global spacing of photons. "
+ "Decrease by half to get 4x more photons at surface of "
+ "this object (or 8x media photons than specified in the globals",
+ min=0.01,
+ max=1.00,
+ default=1.00,
+ )
+
+ ##################################CustomPOV Code############################
+ # Only DUMMIES below for now:
+ replacement_text: StringProperty(
+ name="Declared name:",
+ description="Type the declared name in custom POV code or an external .inc "
+ "it points at. Any POV shape expected e.g: isosurface {}",
+ default="",
+ )
+
+ #############POV specific object properties.############################
+ object_as: StringProperty(maxlen=1024)
+
+ imported_loc: FloatVectorProperty(
+ name="Imported Pov location", precision=6, default=(0.0, 0.0, 0.0)
+ )
+
+ imported_loc_cap: FloatVectorProperty(
+ name="Imported Pov location", precision=6, default=(0.0, 0.0, 2.0)
+ )
+
+ unlock_parameters: BoolProperty(name="Lock", default=False)
+
+ # not in UI yet but used for sor (lathe) / prism... pov primitives
+ curveshape: EnumProperty(
+ name="Povray Shape Type",
+ items=(
+ ("birail", "Birail", ""),
+ ("cairo", "Cairo", ""),
+ ("lathe", "Lathe", ""),
+ ("loft", "Loft", ""),
+ ("prism", "Prism", ""),
+ ("sphere_sweep", "Sphere Sweep", ""),
+ ),
+ default="sphere_sweep",
+ )
+
+ mesh_write_as: EnumProperty(
+ name="Mesh Write As",
+ items=(("blobgrid", "Blob Grid", ""), ("grid", "Grid", ""), ("mesh", "Mesh", "")),
+ default="mesh",
+ )
+
+ object_ior: FloatProperty(name="IOR", description="IOR", min=1.0, max=10.0, default=1.0)
+
+ # shape_as_light = StringProperty(name="Light",maxlen=1024)
+ # fake_caustics_power = FloatProperty(
+ # name="Power", description="Fake caustics power",
+ # min=0.0, max=10.0,default=0.0)
+ # target = BoolProperty(name="Target",description="",default=False)
+ # target_value = FloatProperty(
+ # name="Value", description="",
+ # min=0.0, max=1.0,default=1.0)
+ # refraction = BoolProperty(name="Refraction",description="",default=False)
+ # dispersion = BoolProperty(name="Dispersion",description="",default=False)
+ # dispersion_value = FloatProperty(
+ # name="Dispersion", description="Good values are 1.01 to 1.1. ",
+ # min=1.0, max=1.2,default=1.01)
+ # dispersion_samples = IntProperty(name="Samples",min=2, max=100,default=7)
+ # reflection = BoolProperty(name="Reflection",description="",default=False)
+ # pass_through = BoolProperty(name="Pass through",description="",default=False)
+ no_shadow: BoolProperty(name="No Shadow", default=False)
+
+ no_image: BoolProperty(name="No Image", default=False)
+
+ no_reflection: BoolProperty(name="No Reflection", default=False)
+
+ no_radiosity: BoolProperty(name="No Radiosity", default=False)
+
+ inverse: BoolProperty(name="Inverse", default=False)
+
+ sturm: BoolProperty(name="Sturm", default=False)
+
+ double_illuminate: BoolProperty(name="Double Illuminate", default=False)
+
+ hierarchy: BoolProperty(name="Hierarchy", default=False)
+
+ hollow: BoolProperty(name="Hollow", default=False)
+
+ boundorclip: EnumProperty(
+ name="Boundorclip",
+ items=(
+ ("none", "None", ""),
+ ("bounded_by", "Bounded_by", ""),
+ ("clipped_by", "Clipped_by", ""),
+ ),
+ default="none",
+ )
+
+ boundorclipob: StringProperty(maxlen=1024)
+
+ addboundorclip: BoolProperty(description="", default=False)
+
+ blob_threshold: FloatProperty(name="Threshold", min=0.00, max=10.0, default=0.6)
+
+ blob_strength: FloatProperty(name="Strength", min=-10.00, max=10.0, default=1.00)
+
+ res_u: IntProperty(name="U", min=100, max=1000, default=500)
+
+ res_v: IntProperty(name="V", min=100, max=1000, default=500)
+
+ contained_by: EnumProperty(
+ name="Contained by", items=(("box", "Box", ""), ("sphere", "Sphere", "")), default="box"
+ )
+
+ container_scale: FloatProperty(name="Container Scale", min=0.0, max=10.0, default=1.00)
+
+ threshold: FloatProperty(name="Threshold", min=0.0, max=10.0, default=0.00)
+
+ accuracy: FloatProperty(name="Accuracy", min=0.0001, max=0.1, default=0.001)
+
+ max_gradient: FloatProperty(name="Max Gradient", min=0.0, max=100.0, default=5.0)
+
+ all_intersections: BoolProperty(name="All Intersections", default=False)
+
+ max_trace: IntProperty(name="Max Trace", min=1, max=100, default=1)
+
+ ###########Cylinder
+ def prop_update_cylinder(self, context):
+ """Update POV cylinder primitive parameters not only at creation but anytime they are changed in UI."""
+ if bpy.ops.pov.cylinder_update.poll():
+ bpy.ops.pov.cylinder_update()
+
+ cylinder_radius: FloatProperty(
+ name="Cylinder R", min=0.00, max=10.0, default=0.04, update=prop_update_cylinder
+ )
+
+ cylinder_location_cap: FloatVectorProperty(
+ name="Cylinder Cap Location",
+ subtype="TRANSLATION",
+ description="The position of the 'other' end of the cylinder (relative to object location)",
+ default=(0.0, 0.0, 2.0),
+ update=prop_update_cylinder,
+ )
+
+ imported_cyl_loc: FloatVectorProperty(
+ name="Imported Pov location", precision=6, default=(0.0, 0.0, 0.0)
+ )
+
+ imported_cyl_loc_cap: FloatVectorProperty(
+ name="Imported Pov location", precision=6, default=(0.0, 0.0, 2.0)
+ )
+
+ ###########Sphere
+ def prop_update_sphere(self, context):
+
+ """Update POV sphere primitive parameters not only at creation but anytime they are changed in UI."""
+
+ bpy.ops.pov.sphere_update()
+
+ sphere_radius: FloatProperty(
+ name="Sphere radius", min=0.00, max=10.0, default=0.5, update=prop_update_sphere
+ )
+
+ ###########Cone
+ def prop_update_cone(self, context):
+
+ """Update POV cone primitive parameters not only at creation but anytime they are changed in UI."""
+
+ bpy.ops.pov.cone_update()
+
+ cone_base_radius: FloatProperty(
+ name="Base radius",
+ description="The first radius of the cone",
+ default=1.0,
+ min=0.01,
+ max=100.0,
+ update=prop_update_cone,
+ )
+
+ cone_cap_radius: FloatProperty(
+ name="Cap radius",
+ description="The second radius of the cone",
+ default=0.3,
+ min=0.0,
+ max=100.0,
+ update=prop_update_cone,
+ )
+
+ cone_segments: IntProperty(
+ name="Segments",
+ description="Radial segmentation of proxy mesh",
+ default=16,
+ min=3,
+ max=265,
+ update=prop_update_cone,
+ )
+
+ cone_height: FloatProperty(
+ name="Height",
+ description="Height of the cone",
+ default=2.0,
+ min=0.01,
+ max=100.0,
+ update=prop_update_cone,
+ )
+
+ cone_base_z: FloatProperty()
+
+ cone_cap_z: FloatProperty()
+
+ ###########Parametric
+ def prop_update_parametric(self, context):
+
+ """Update POV parametric surface primitive parameters not only at creation but anytime they are changed in UI."""
+
+ bpy.ops.pov.parametric_update()
+
+ u_min: FloatProperty(name="U Min", description="", default=0.0, update=prop_update_parametric)
+
+ v_min: FloatProperty(name="V Min", description="", default=0.0, update=prop_update_parametric)
+
+ u_max: FloatProperty(name="U Max", description="", default=6.28, update=prop_update_parametric)
+
+ v_max: FloatProperty(name="V Max", description="", default=12.57, update=prop_update_parametric)
+
+ x_eq: StringProperty(
+ maxlen=1024, default="cos(v)*(1+cos(u))*sin(v/8)", update=prop_update_parametric
+ )
+
+ y_eq: StringProperty(
+ maxlen=1024, default="sin(u)*sin(v/8)+cos(v/8)*1.5", update=prop_update_parametric
+ )
+
+ z_eq: StringProperty(
+ maxlen=1024, default="sin(v)*(1+cos(u))*sin(v/8)", update=prop_update_parametric
+ )
+
+ ###########Torus
+
+ def prop_update_torus(self, context):
+
+ """Update POV torus primitive parameters not only at creation but anytime they are changed in UI."""
+
+ bpy.ops.pov.torus_update()
+
+ torus_major_segments: IntProperty(
+ name="Segments",
+ description="Radial segmentation of proxy mesh",
+ default=48,
+ min=3,
+ max=720,
+ update=prop_update_torus,
+ )
+
+ torus_minor_segments: IntProperty(
+ name="Segments",
+ description="Cross-section segmentation of proxy mesh",
+ default=12,
+ min=3,
+ max=720,
+ update=prop_update_torus,
+ )
+
+ torus_major_radius: FloatProperty(
+ name="Major radius",
+ description="Major radius",
+ min=0.00,
+ max=100.00,
+ default=1.0,
+ update=prop_update_torus,
+ )
+
+ torus_minor_radius: FloatProperty(
+ name="Minor radius",
+ description="Minor radius",
+ min=0.00,
+ max=100.00,
+ default=0.25,
+ update=prop_update_torus,
+ )
+
+ ###########Rainbow
+ arc_angle: FloatProperty(
+ name="Arc angle",
+ description="The angle of the raynbow arc in degrees",
+ default=360,
+ min=0.01,
+ max=360.0,
+ )
+
+ falloff_angle: FloatProperty(
+ name="Falloff angle",
+ description="The angle after which rainbow dissolves into background",
+ default=360,
+ min=0.0,
+ max=360,
+ )
+
+ ###########HeightFields
+
+ quality: IntProperty(name="Quality", description="", default=100, min=1, max=100)
+
+ hf_filename: StringProperty(maxlen=1024)
+
+ hf_gamma: FloatProperty(name="Gamma", description="Gamma", min=0.0001, max=20.0, default=1.0)
+
+ hf_premultiplied: BoolProperty(name="Premultiplied", description="Premultiplied", default=True)
+
+ hf_smooth: BoolProperty(name="Smooth", description="Smooth", default=False)
+
+ hf_water: FloatProperty(
+ name="Water Level", description="Wather Level", min=0.00, max=1.00, default=0.0
+ )
+
+ hf_hierarchy: BoolProperty(name="Hierarchy", description="Height field hierarchy", default=True)
+
+ ##############Superellipsoid
+ def prop_update_superellipsoid(self, context):
+
+ """Update POV superellipsoid primitive parameters not only at creation but anytime they are changed in UI."""
+
+ bpy.ops.pov.superellipsoid_update()
+
+ se_param1: FloatProperty(name="Parameter 1", description="", min=0.00, max=10.0, default=0.04)
+
+ se_param2: FloatProperty(name="Parameter 2", description="", min=0.00, max=10.0, default=0.04)
+
+ se_u: IntProperty(
+ name="U-segments",
+ description="radial segmentation",
+ default=20,
+ min=4,
+ max=265,
+ update=prop_update_superellipsoid,
+ )
+
+ se_v: IntProperty(
+ name="V-segments",
+ description="lateral segmentation",
+ default=20,
+ min=4,
+ max=265,
+ update=prop_update_superellipsoid,
+ )
+
+ se_n1: FloatProperty(
+ name="Ring manipulator",
+ description="Manipulates the shape of the Ring",
+ default=1.0,
+ min=0.01,
+ max=100.0,
+ update=prop_update_superellipsoid,
+ )
+
+ se_n2: FloatProperty(
+ name="Cross manipulator",
+ description="Manipulates the shape of the cross-section",
+ default=1.0,
+ min=0.01,
+ max=100.0,
+ update=prop_update_superellipsoid,
+ )
+
+ se_edit: EnumProperty(
+ items=[("NOTHING", "Nothing", ""), ("NGONS", "N-Gons", ""), ("TRIANGLES", "Triangles", "")],
+ name="Fill up and down",
+ description="",
+ default="TRIANGLES",
+ update=prop_update_superellipsoid,
+ )
+
+ #############Used for loft but also Superellipsoid, etc.
+ curveshape: EnumProperty(
+ name="Povray Shape Type",
+ items=(
+ ("birail", "Birail", ""),
+ ("cairo", "Cairo", ""),
+ ("lathe", "Lathe", ""),
+ ("loft", "Loft", ""),
+ ("prism", "Prism", ""),
+ ("sphere_sweep", "Sphere Sweep", ""),
+ ("sor", "Surface of Revolution", ""),
+ ),
+ default="sphere_sweep",
+ )
+
+ #############Supertorus
+ def prop_update_supertorus(self, context):
+
+ """Update POV supertorus primitive parameters not only at creation but anytime they are changed in UI."""
+
+ bpy.ops.pov.supertorus_update()
+
+ st_major_radius: FloatProperty(
+ name="Major radius",
+ description="Major radius",
+ min=0.00,
+ max=100.00,
+ default=1.0,
+ update=prop_update_supertorus,
+ )
+
+ st_minor_radius: FloatProperty(
+ name="Minor radius",
+ description="Minor radius",
+ min=0.00,
+ max=100.00,
+ default=0.25,
+ update=prop_update_supertorus,
+ )
+
+ st_ring: FloatProperty(
+ name="Ring",
+ description="Ring manipulator",
+ min=0.0001,
+ max=100.00,
+ default=1.00,
+ update=prop_update_supertorus,
+ )
+
+ st_cross: FloatProperty(
+ name="Cross",
+ description="Cross manipulator",
+ min=0.0001,
+ max=100.00,
+ default=1.00,
+ update=prop_update_supertorus,
+ )
+
+ st_accuracy: FloatProperty(
+ name="Accuracy", description="Supertorus accuracy", min=0.00001, max=1.00, default=0.001
+ )
+
+ st_max_gradient: FloatProperty(
+ name="Gradient",
+ description="Max gradient",
+ min=0.0001,
+ max=100.00,
+ default=10.00,
+ update=prop_update_supertorus,
+ )
+
+ st_R: FloatProperty(
+ name="big radius",
+ description="The radius inside the tube",
+ default=1.0,
+ min=0.01,
+ max=100.0,
+ update=prop_update_supertorus,
+ )
+
+ st_r: FloatProperty(
+ name="small radius",
+ description="The radius of the tube",
+ default=0.3,
+ min=0.01,
+ max=100.0,
+ update=prop_update_supertorus,
+ )
+
+ st_u: IntProperty(
+ name="U-segments",
+ description="radial segmentation",
+ default=16,
+ min=3,
+ max=265,
+ update=prop_update_supertorus,
+ )
+
+ st_v: IntProperty(
+ name="V-segments",
+ description="lateral segmentation",
+ default=8,
+ min=3,
+ max=265,
+ update=prop_update_supertorus,
+ )
+
+ st_n1: FloatProperty(
+ name="Ring manipulator",
+ description="Manipulates the shape of the Ring",
+ default=1.0,
+ min=0.01,
+ max=100.0,
+ update=prop_update_supertorus,
+ )
+
+ st_n2: FloatProperty(
+ name="Cross manipulator",
+ description="Manipulates the shape of the cross-section",
+ default=1.0,
+ min=0.01,
+ max=100.0,
+ update=prop_update_supertorus,
+ )
+
+ st_ie: BoolProperty(
+ name="Use Int.+Ext. radii",
+ description="Use internal and external radii",
+ default=False,
+ update=prop_update_supertorus,
+ )
+
+ st_edit: BoolProperty(
+ name="", description="", default=False, options={"HIDDEN"}, update=prop_update_supertorus
+ )
+
+ ########################Loft
+ loft_n: IntProperty(
+ name="Segments", description="Vertical segments", default=16, min=3, max=720
+ )
+
+ loft_rings_bottom: IntProperty(
+ name="Bottom", description="Bottom rings", default=5, min=2, max=100
+ )
+
+ loft_rings_side: IntProperty(name="Side", description="Side rings", default=10, min=2, max=100)
+
+ loft_thick: FloatProperty(
+ name="Thickness",
+ description="Manipulates the shape of the Ring",
+ default=0.3,
+ min=0.01,
+ max=1.0,
+ )
+
+ loft_r: FloatProperty(name="Radius", description="Radius", default=1, min=0.01, max=10)
+
+ loft_height: FloatProperty(
+ name="Height",
+ description="Manipulates the shape of the Ring",
+ default=2,
+ min=0.01,
+ max=10.0,
+ )
+
+ ###################Prism
+ prism_n: IntProperty(name="Sides", description="Number of sides", default=5, min=3, max=720)
+
+ prism_r: FloatProperty(name="Radius", description="Radius", default=1.0)
+
+ ##################Isosurface
+ iso_function_text: StringProperty(
+ name="Function Text", maxlen=1024
+ ) # ,update=iso_props_update_callback)
+
+ ##################PolygonToCircle
+ polytocircle_resolution: IntProperty(
+ name="Resolution", description="", default=3, min=0, max=256
+ )
+
+ polytocircle_ngon: IntProperty(name="NGon", description="", min=3, max=64, default=5)
+
+ polytocircle_ngonR: FloatProperty(name="NGon Radius", description="", default=0.3)
+
+ polytocircle_circleR: FloatProperty(name="Circle Radius", description="", default=1.0)
+
+ ###############################################################################
+ # Modifiers POV properties.
+ ###############################################################################
+ # class RenderPovSettingsModifier(PropertyGroup):
+ boolean_mod: EnumProperty(
+ name="Operation",
+ description="Choose the type of calculation for Boolean modifier",
+ items=(
+ ("BMESH", "Use the BMesh Boolean Solver", ""),
+ ("CARVE", "Use the Carve Boolean Solver", ""),
+ ("POV", "Use POV Constructive Solid Geometry", ""),
+ ),
+ default="BMESH",
+ )
+
+ #################Avogadro
+ # filename_ext = ".png"
+
+ # filter_glob = StringProperty(
+ # default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
+ # options={'HIDDEN'},
+ # )
+
+
+classes = (RenderPovSettingsObject,)
+
+
+def register():
+ for cls in classes:
+ register_class(cls)
+ bpy.types.Object.pov = PointerProperty(type=RenderPovSettingsObject)
+
+
+def unregister():
+ del bpy.types.Object.pov
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/render.py b/render_povray/render.py
index c4a93ebd..45a94912 100644..100755
--- a/render_povray/render.py
+++ b/render_povray/render.py
@@ -17,200 +17,79 @@
# #**** END GPL LICENSE BLOCK #****
# <pep8 compliant>
-
+"""Wirte the POV file using this file's functions and some from other modules then render it."""
import bpy
import subprocess
import os
-import sys
+from sys import platform
import time
-from math import atan, pi, degrees, sqrt, cos, sin
-####################
-## Faster mesh export
-import numpy as np
-####################
+from math import (
+ pi,
+) # maybe move to scenography.py and topology_*****_data.py respectively with smoke and matrix
+
import re
-import random
-import platform #
-import subprocess #
import tempfile # generate temporary files with random names
from bpy.types import Operator
-from imghdr import what # imghdr is a python lib to identify image file types
-from bpy.utils import register_class
+from bpy.utils import register_class, unregister_class
-from . import df3 # for smoke rendering
+from . import (
+ scripting,
+) # for writing, importing and rendering directly POV Scene Description Language items
+from . import scenography # for atmosphere, environment, effects, lighting, camera
from . import shading # for BI POV shaders emulation
-from . import primitives # for import and export of POV specific primitives
-from . import nodes # for POV specific nodes
-
-##############################SF###########################
-##############find image texture
-def imageFormat(imgF):
- """Identify input image filetypes to transmit to POV."""
- # First use the below explicit extensions to identify image file prospects
- ext = {
- 'JPG': "jpeg",
- 'JPEG': "jpeg",
- 'GIF': "gif",
- 'TGA': "tga",
- 'IFF': "iff",
- 'PPM': "ppm",
- 'PNG': "png",
- 'SYS': "sys",
- 'TIFF': "tiff",
- 'TIF': "tiff",
- 'EXR': "exr",
- 'HDR': "hdr",
- }.get(os.path.splitext(imgF)[-1].upper(), "")
- # Then, use imghdr to really identify the filetype as it can be different
- if not ext:
- # maybe add a check for if path exists here?
- print(" WARNING: texture image has no extension") # too verbose
-
- ext = what(imgF) # imghdr is a python lib to identify image file types
- return ext
-
-
-def imgMap(ts):
- """Translate mapping type from Blender UI to POV syntax and return that string."""
- image_map = ""
- texdata = bpy.data.textures[ts.texture]
- if ts.mapping == 'FLAT':
- image_map = "map_type 0 "
- elif ts.mapping == 'SPHERE':
- image_map = "map_type 1 "
- elif ts.mapping == 'TUBE':
- image_map = "map_type 2 "
-
- ## map_type 3 and 4 in development (?) (ENV in pov 3.8)
- ## for POV-Ray, currently they just seem to default back to Flat (type 0)
- # elif ts.mapping=="?":
- # image_map = " map_type 3 "
- # elif ts.mapping=="?":
- # image_map = " map_type 4 "
- if ts.use_interpolation: # Available if image sampling class reactivated?
- image_map += " interpolate 2 "
- if texdata.extension == 'CLIP':
- image_map += " once "
- # image_map += "}"
- # if ts.mapping=='CUBE':
- # image_map+= "warp { cubic } rotate <-90,0,180>"
- # no direct cube type mapping. Though this should work in POV 3.7
- # it doesn't give that good results(best suited to environment maps?)
- # if image_map == "":
- # print(" No texture image found ")
- return image_map
-
-
-def imgMapTransforms(ts):
- """Translate mapping transformations from Blender UI to POV syntax and return that string."""
- # XXX TODO: unchecked textures give error of variable referenced before assignment XXX
- # POV-Ray "scale" is not a number of repetitions factor, but ,its
- # inverse, a standard scale factor.
- # 0.5 Offset is needed relatively to scale because center of the
- # scale is 0.5,0.5 in blender and 0,0 in POV
- # Strange that the translation factor for scale is not the same as for
- # translate.
- # TODO: verify both matches with blender internal.
- image_map_transforms = ""
- image_map_transforms = (
- "scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>"
- % (
- ts.scale[0],
- ts.scale[1],
- ts.scale[2],
- ts.offset[0],
- ts.offset[1],
- ts.offset[2],
- )
- )
- # image_map_transforms = (" translate <-0.5,-0.5,0.0> scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
- # ( 1.0 / ts.scale.x,
- # 1.0 / ts.scale.y,
- # 1.0 / ts.scale.z,
- # (0.5 / ts.scale.x) + ts.offset.x,
- # (0.5 / ts.scale.y) + ts.offset.y,
- # ts.offset.z))
- # image_map_transforms = ("translate <-0.5,-0.5,0> scale <-1,-1,1> * <%.4g,%.4g,%.4g> translate <0.5,0.5,0> + <%.4g,%.4g,%.4g>" % \
- # (1.0 / ts.scale.x,
- # 1.0 / ts.scale.y,
- # 1.0 / ts.scale.z,
- # ts.offset.x,
- # ts.offset.y,
- # ts.offset.z))
- return image_map_transforms
-
-
-def imgMapBG(wts):
- """Translate world mapping from Blender UI to POV syntax and return that string."""
- tex = bpy.data.textures[wts.texture]
- image_mapBG = ""
- # texture_coords refers to the mapping of world textures:
- if wts.texture_coords == 'VIEW' or wts.texture_coords == 'GLOBAL':
- image_mapBG = " map_type 0 "
- elif wts.texture_coords == 'ANGMAP':
- image_mapBG = " map_type 1 "
- elif wts.texture_coords == 'TUBE':
- image_mapBG = " map_type 2 "
-
- if tex.use_interpolation:
- image_mapBG += " interpolate 2 "
- if tex.extension == 'CLIP':
- image_mapBG += " once "
- # image_mapBG += "}"
- # if wts.mapping == 'CUBE':
- # image_mapBG += "warp { cubic } rotate <-90,0,180>"
- # no direct cube type mapping. Though this should work in POV 3.7
- # it doesn't give that good results(best suited to environment maps?)
- # if image_mapBG == "":
- # print(" No background texture image found ")
- return image_mapBG
-
-
-def path_image(image):
- """Conform a path string to POV syntax to avoid POV errors."""
- return bpy.path.abspath(image.filepath, library=image.library).replace(
- "\\", "/"
- )
- # .replace("\\","/") to get only forward slashes as it's what POV prefers,
- # even on windows
+from . import object_mesh_topology # for mesh based geometry
+from . import object_curve_topology # for curves based geometry
+
+# from . import object_primitives # for import and export of POV specific primitives
-# end find image texture
-# -----------------------------------------------------------------------------
+from .scenography import image_format, img_map, img_map_transforms, path_image
+
+from .shading import write_object_material
+from .object_primitives import write_object_modifiers
def string_strip_hyphen(name):
+
"""Remove hyphen characters from a string to avoid POV errors."""
+
return name.replace("-", "")
-def safety(name, Level):
+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 povHasnoSpecularMaps function to create the finish map trick and
+ 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
- Level -- the enum number of the Level being written:
- Level=1 is for texture with No specular nor Mirror reflection
- Level=2 is for texture with translation of spec and mir levels
+ 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
- Level=3 is for texture with Maximum Spec and Mirror
+ ref_level_bound=3 is for texture with Maximum Spec and Mirror
"""
-
- try:
- if int(name) > 0:
- prefix = "shader"
- except:
- prefix = ""
+ # 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 exXXXception occurred: {}'.format(e))
+ # prefix = "" # rewritten below...
prefix = "shader_"
name = string_strip_hyphen(name)
- if Level == 2:
+ if ref_level_bound == 2:
return prefix + name
- elif Level == 1:
+ # implicit else-if (no return yet)
+ if ref_level_bound == 1:
return prefix + name + "0" # used for 0 of specular map
- elif Level == 3:
+ # implicit else-if (no return yet)
+ if ref_level_bound == 3:
return prefix + name + "1" # used for 1 of specular map
@@ -220,174 +99,107 @@ def safety(name, Level):
csg_list = []
-def is_renderable(scene, ob):
+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(scene):
- return [ob for ob in bpy.data.objects if is_renderable(scene, ob)]
+ """test for non hidden, non boolean operands objects to render"""
+ return [ob for ob in bpy.data.objects if is_renderable(ob)]
-def no_renderable_objects(scene):
- return [ob for ob in csg_list]
+def no_renderable_objects():
+ """Boolean operands only. Not to render"""
+ return list(csg_list)
-tabLevel = 0
+tab_level = 0
unpacked_images = []
user_dir = bpy.utils.resource_path('USER')
preview_dir = os.path.join(user_dir, "preview")
## Make sure Preview directory exists and is empty
-smokePath = os.path.join(preview_dir, "smoke.df3")
-'''
-def write_global_setting(scene,file):
- file.write("global_settings {\n")
- file.write(" assumed_gamma %.6f\n"%scene.pov.assumed_gamma)
- if scene.pov.global_settings_advanced:
- if scene.pov.radio_enable == False:
- 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(" charset %s\n"%scene.pov.charset)
- file.write(" max_trace_level %s\n"%scene.pov.max_trace_level)
- file.write(" max_intersections %s\n"%scene.pov.max_intersections)
- file.write(" number_of_waves %s\n"%scene.pov.number_of_waves)
- file.write(" noise_generator %s\n"%scene.pov.noise_generator)
-
- # 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")
-
- if scene.pov.radio_enable:
- file.write(" radiosity {\n")
- file.write(" pretrace_start %.6f\n"%scene.pov.radio_pretrace_start)
- file.write(" pretrace_end %.6f\n"%scene.pov.radio_pretrace_end)
- file.write(" count %s\n"%scene.pov.radio_count)
- file.write(" nearest_count %s\n"%scene.pov.radio_nearest_count)
- file.write(" error_bound %.6f\n"%scene.pov.radio_error_bound)
- file.write(" recursion_limit %s\n"%scene.pov.radio_recursion_limit)
- file.write(" low_error_factor %.6f\n"%scene.pov.radio_low_error_factor)
- file.write(" gray_threshold %.6f\n"%scene.pov.radio_gray_threshold)
- file.write(" maximum_reuse %.6f\n"%scene.pov.radio_maximum_reuse)
- file.write(" minimum_reuse %.6f\n"%scene.pov.radio_minimum_reuse)
- file.write(" brightness %.6f\n"%scene.pov.radio_brightness)
- file.write(" adc_bailout %.6f\n"%scene.pov.radio_adc_bailout)
- if scene.pov.radio_normal:
- file.write(" normal on\n")
- if scene.pov.radio_always_sample:
- file.write(" always_sample on\n")
- if scene.pov.radio_media:
- file.write(" media on\n")
- if scene.pov.radio_subsurface:
- file.write(" subsurface on\n")
- file.write(" }\n")
-
- if scene.pov.photon_enable:
- file.write(" photons {\n")
- if scene.pov.photon_enable_count:
- file.write(" count %s\n"%scene.pov.photon_count)
- else:
- file.write(" spacing %.6g\n"%scene.pov.photon_spacing)
- if scene.pov.photon_gather:
- file.write(" gather %s, %s\n"%(scene.pov.photon_gather_min,scene.pov.photon_gather_max))
- if scene.pov.photon_autostop:
- file.write(" autostop %.4g\n"%scene.pov.photon_autostop_value)
- if scene.pov.photon_jitter_enable:
- file.write(" jitter %.4g\n"%scene.pov.photon_jitter)
- file.write(" max_trace_level %s\n"%scene.pov.photon_max_trace_level)
- if scene.pov.photon_adc:
- file.write(" adc_bailout %.6f\n"%scene.pov.photon_adc_bailout)
- if scene.pov.photon_media_enable:
- file.write(" media %s, %s\n"%(scene.pov.photon_media_steps,scene.pov.photon_media_factor))
- if scene.pov.photon_map_file_save_load in {'save'}:
- filePhName = 'Photon_map_file.ph'
- if scene.pov.photon_map_file != '':
- filePhName = scene.pov.photon_map_file+'.ph'
- filePhDir = tempfile.gettempdir()
- path = bpy.path.abspath(scene.pov.photon_map_dir)
- if os.path.exists(path):
- filePhDir = path
- fullFileName = os.path.join(filePhDir,filePhName)
- file.write(' save_file "%s"\n'%fullFileName)
- scene.pov.photon_map_file = fullFileName
- if scene.pov.photon_map_file_save_load in {'load'}:
- fullFileName = bpy.path.abspath(scene.pov.photon_map_file)
- if os.path.exists(fullFileName):
- file.write(' load_file "%s"\n'%fullFileName)
- file.write("}\n")
- file.write("}\n")
+smoke_path = os.path.join(preview_dir, "smoke.df3")
+
'''
+# 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
-def write_object_modifiers(scene, ob, File):
- """Translate some object level POV statements from Blender UI
- to POV syntax and write to exported file """
+# 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")
- # Maybe return that string to be added instead of directly written.
+'''
- '''XXX WIP
- onceCSG = 0
- for mod in ob.modifiers:
- if onceCSG == 0:
- if mod :
- if mod.type == 'BOOLEAN':
- if ob.pov.boolean_mod == "POV":
- File.write("\tinside_vector <%.6g, %.6g, %.6g>\n" %
- (ob.pov.inside_vector[0],
- ob.pov.inside_vector[1],
- ob.pov.inside_vector[2]))
- onceCSG = 1
- '''
- 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 write_object_modifiers(scene, 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
+# onceCSG = 0
+# for mod in ob.modifiers:
+# if onceCSG == 0:
+# if mod :
+# if mod.type == 'BOOLEAN':
+# if ob.pov.boolean_mod == "POV":
+# File.write("\tinside_vector <%.6g, %.6g, %.6g>\n" %
+# (ob.pov.inside_vector[0],
+# ob.pov.inside_vector[1],
+# ob.pov.inside_vector[2]))
+# onceCSG = 1
+# '''
+
+# 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 write_pov(filename, scene=None, info_callback=None):
@@ -406,12 +218,8 @@ def write_pov(filename, scene=None, info_callback=None):
world = scene.world
global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
comments = scene.pov.comments_enable and not scene.pov.tempfiles_enable
- linebreaksinlists = (
- scene.pov.list_lf_enable and not scene.pov.tempfiles_enable
- )
- feature_set = bpy.context.preferences.addons[
- __package__
- ].preferences.branch_feature_set_povray
+ linebreaksinlists = scene.pov.list_lf_enable and not scene.pov.tempfiles_enable
+ feature_set = bpy.context.preferences.addons[__package__].preferences.branch_feature_set_povray
using_uberpov = feature_set == 'uberpov'
pov_binary = PovrayRender._locate_binary()
@@ -420,73 +228,64 @@ def write_pov(filename, scene=None, info_callback=None):
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"
- )
+ 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"
- )
+ print("The name of the binary suggests you are probably rendering with standard POV engine")
- def setTab(tabtype, spaces):
- TabStr = ""
+ def set_tab(tabtype, spaces):
+ tab_str = ""
if tabtype == 'NONE':
- TabStr = ""
+ tab_str = ""
elif tabtype == 'TAB':
- TabStr = "\t"
+ tab_str = "\t"
elif tabtype == 'SPACE':
- TabStr = spaces * " "
- return TabStr
+ tab_str = spaces * " "
+ return tab_str
- tab = setTab(scene.pov.indentation_character, scene.pov.indentation_spaces)
+ tab = set_tab(scene.pov.indentation_character, scene.pov.indentation_spaces)
if not scene.pov.tempfiles_enable:
- def tabWrite(str_o):
+ def tab_write(str_o):
"""Indent POV syntax from brackets levels and write to exported file """
- global tabLevel
- brackets = (
- str_o.count("{")
- - str_o.count("}")
- + str_o.count("[")
- - str_o.count("]")
- )
+ global tab_level
+ brackets = str_o.count("{") - str_o.count("}") + str_o.count("[") - str_o.count("]")
if brackets < 0:
- tabLevel = tabLevel + brackets
- if tabLevel < 0:
- print("Indentation Warning: tabLevel = %s" % tabLevel)
- tabLevel = 0
- if tabLevel >= 1:
- file.write("%s" % tab * tabLevel)
+ 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:
- tabLevel = tabLevel + brackets
+ tab_level = tab_level + brackets
else:
- def tabWrite(str_o):
+ def tab_write(str_o):
"""write directly to exported file if user checked autonamed temp files (faster)."""
file.write(str_o)
- def uniqueName(name, nameSeq):
+ def unique_name(name, name_seq):
"""Increment any generated POV name that could get identical to avoid collisions"""
- if name not in nameSeq:
+ if name not in name_seq:
name = string_strip_hyphen(name)
return name
name_orig = name
i = 1
- while name in nameSeq:
+ while name in name_seq:
name = "%s_%.3d" % (name_orig, i)
i += 1
name = string_strip_hyphen(name)
return name
- def writeMatrix(matrix):
+ def write_matrix(matrix):
"""Translate some tranform matrix from Blender UI
to POV syntax and write to exported file """
- tabWrite(
+ tab_write(
"matrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n"
% (
matrix[0][0],
@@ -504,1539 +303,12 @@ def write_pov(filename, scene=None, info_callback=None):
)
)
- def MatrixAsPovString(matrix):
- """Translate some tranform matrix from Blender UI
- to POV syntax and return that string """
- sMatrix = (
- "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],
- )
- )
- return sMatrix
-
- def writeObjectMaterial(material, ob):
- """Translate some object level material from Blender UI (VS data level)
- to POV interior{} syntax and write it to exported file """
-
- # DH - modified some variables to be function local, avoiding RNA write
- # this should be checked to see if it is functionally correct
-
- # Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
- # if material and material.transparency_method == 'RAYTRACE':
- if material:
- # But there can be only one!
- if (
- material.pov_subsurface_scattering.use
- ): # SSS IOR get highest priority
- tabWrite("interior {\n")
- tabWrite("ior %.6f\n" % material.pov_subsurface_scattering.ior)
- # Then the raytrace IOR taken from raytrace transparency properties and used for
- # reflections if IOR Mirror option is checked.
- elif material.pov.mirror_use_IOR:
- tabWrite("interior {\n")
- tabWrite("ior %.6f\n" % material.pov_raytrace_transparency.ior)
- elif material.pov.transparency_method == 'Z_TRANSPARENCY':
- tabWrite("interior {\n")
- tabWrite("ior 1.0\n")
- else:
- tabWrite("interior {\n")
- tabWrite("ior %.6f\n" % material.pov_raytrace_transparency.ior)
-
- pov_fake_caustics = False
- pov_photons_refraction = False
- pov_photons_reflection = False
-
- if material.pov.photons_reflection:
- pov_photons_reflection = True
- if not material.pov.refraction_caustics:
- pov_fake_caustics = False
- pov_photons_refraction = False
- elif material.pov.refraction_type == "1":
- pov_fake_caustics = True
- pov_photons_refraction = False
- elif material.pov.refraction_type == "2":
- pov_fake_caustics = False
- pov_photons_refraction = True
-
- # If only Raytrace transparency is set, its IOR will be used for refraction, but user
- # can set up 'un-physical' fresnel reflections in raytrace mirror parameters.
- # Last, if none of the above is specified, user can set up 'un-physical' fresnel
- # reflections in raytrace mirror parameters. And pov IOR defaults to 1.
- if material.pov.caustics_enable:
- if pov_fake_caustics:
- tabWrite(
- "caustics %.3g\n" % material.pov.fake_caustics_power
- )
- if pov_photons_refraction:
- # Default of 1 means no dispersion
- tabWrite(
- "dispersion %.6f\n" % material.pov.photons_dispersion
- )
- tabWrite(
- "dispersion_samples %.d\n"
- % material.pov.photons_dispersion_samples
- )
- # TODO
- # Other interior args
- if (
- material.pov.use_transparency
- and material.pov.transparency_method == 'RAYTRACE'
- ):
- # fade_distance
- # In Blender this value has always been reversed compared to what tooltip says.
- # 100.001 rather than 100 so that it does not get to 0
- # which deactivates the feature in POV
- tabWrite(
- "fade_distance %.3g\n"
- % (100.001 - material.pov_raytrace_transparency.depth_max)
- )
- # fade_power
- tabWrite(
- "fade_power %.3g\n"
- % material.pov_raytrace_transparency.falloff
- )
- # fade_color
- tabWrite(
- "fade_color <%.3g, %.3g, %.3g>\n"
- % material.pov.interior_fade_color[:]
- )
-
- # (variable) dispersion_samples (constant count for now)
- tabWrite("}\n")
- if (
- material.pov.photons_reflection
- or material.pov.refraction_type == "2"
- ):
- tabWrite("photons{")
- tabWrite("target %.3g\n" % ob.pov.spacing_multiplier)
- if not ob.pov.collect_photons:
- tabWrite("collect off\n")
- if pov_photons_refraction:
- tabWrite("refraction on\n")
- if pov_photons_reflection:
- tabWrite("reflection on\n")
- tabWrite("}\n")
-
- materialNames = {}
+ material_names_dictionary = {}
DEF_MAT_NAME = "" # or "Default"?
- def exportCamera():
- """Translate camera from Blender UI to POV syntax and write to exported file."""
- camera = scene.camera
-
- # DH disabled for now, this isn't the correct context
- active_object = (
- None
- ) # bpy.context.active_object # does not always work MR
- matrix = global_matrix @ camera.matrix_world
- focal_point = camera.data.dof.focus_distance
-
- # compute resolution
- Qsize = render.resolution_x / render.resolution_y
- tabWrite(
- "#declare camLocation = <%.6f, %.6f, %.6f>;\n"
- % matrix.translation[:]
- )
- tabWrite(
- "#declare camLookAt = <%.6f, %.6f, %.6f>;\n"
- % tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
- )
-
- tabWrite("camera {\n")
- if (
- scene.pov.baking_enable
- and active_object
- and active_object.type == 'MESH'
- ):
- tabWrite(
- "mesh_camera{ 1 3\n"
- ) # distribution 3 is what we want here
- tabWrite("mesh{%s}\n" % active_object.name)
- tabWrite("}\n")
- tabWrite("location <0,0,.01>")
- tabWrite("direction <0,0,-1>")
-
- else:
- if camera.data.type == 'ORTHO':
- SensorHeightRatio = render.resolution_x * camera.data.ortho_scale / render.resolution_y
- tabWrite("orthographic\n")
- # Blender angle is radian so should be converted to degrees:
- # % (camera.data.angle * (180.0 / pi) )
- # but actually argument is not compulsory after angle in pov ortho mode
- tabWrite("angle\n")
- tabWrite("right <%6f, 0, 0>\n" % -camera.data.ortho_scale)
- tabWrite("location <0, 0, 0>\n")
- tabWrite("look_at <0, 0, -1>\n")
- tabWrite("up <0, %6f, 0>\n" % (camera.data.ortho_scale / Qsize))
-
- elif camera.data.type == 'PANO':
- tabWrite("panoramic\n")
- tabWrite("location <0, 0, 0>\n")
- tabWrite("look_at <0, 0, -1>\n")
- tabWrite("right <%s, 0, 0>\n" % -Qsize)
- tabWrite("up <0, 1, 0>\n")
- tabWrite(
- "angle %f\n" % (360.0 * atan(16.0 / camera.data.lens) / pi)
- )
- elif camera.data.type == 'PERSP':
- # Standard camera otherwise would be default in pov
- tabWrite("location <0, 0, 0>\n")
- tabWrite("look_at <0, 0, -1>\n")
- tabWrite("right <%s, 0, 0>\n" % -Qsize)
- tabWrite("up <0, 1, 0>\n")
- tabWrite(
- "angle %f\n" % ( 2 * atan(camera.data.sensor_width / 2 / camera.data.lens) * 180.0 / pi )
- )
-
- tabWrite(
- "rotate <%.6f, %.6f, %.6f>\n"
- % tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
- )
- tabWrite("translate <%.6f, %.6f, %.6f>\n" % matrix.translation[:])
- if camera.data.dof.use_dof and (
- focal_point != 0 or camera.data.dof.focus_object
- ):
- tabWrite(
- "aperture %.3g\n"
- % (1 / camera.data.dof.aperture_fstop * 1000)
- )
- tabWrite(
- "blur_samples %d %d\n"
- % (
- camera.data.pov.dof_samples_min,
- camera.data.pov.dof_samples_max,
- )
- )
- tabWrite("variance 1/%d\n" % camera.data.pov.dof_variance)
- tabWrite("confidence %.3g\n" % camera.data.pov.dof_confidence)
- if camera.data.dof.focus_object:
- focalOb = scene.objects[camera.data.dof.focus_object.name]
- matrixBlur = global_matrix @ focalOb.matrix_world
- tabWrite(
- "focal_point <%.4f,%.4f,%.4f>\n"
- % matrixBlur.translation[:]
- )
- else:
- tabWrite("focal_point <0, 0, %f>\n" % focal_point)
- if camera.data.pov.normal_enable:
- tabWrite(
- "normal {%s %.4f turbulence %.4f scale %.4f}\n"
- % (
- camera.data.pov.normal_patterns,
- camera.data.pov.cam_normal,
- camera.data.pov.turbulence,
- camera.data.pov.scale,
- )
- )
- tabWrite("}\n")
-
- def exportLamps(lamps):
- """Translate lights from Blender UI to POV syntax and write to exported file."""
-
- # Incremented after each lamp export to declare its target
- # currently used for Fresnel diffuse shader as their slope vector:
- global lampCount
- lampCount = 0
- # Get all lamps
- for ob in lamps:
- lamp = ob.data
-
- matrix = global_matrix @ ob.matrix_world
-
- # Color is no longer modified by energy
- color = tuple([c for c in lamp.color])
-
- tabWrite("light_source {\n")
- tabWrite("< 0,0,0 >\n")
- tabWrite("color srgb<%.3g, %.3g, %.3g>\n" % color)
-
- if lamp.type == 'POINT':
- pass
- elif lamp.type == 'SPOT':
- tabWrite("spotlight\n")
-
- # Falloff is the main radius from the centre line
- tabWrite(
- "falloff %.2f\n" % (degrees(lamp.spot_size) / 2.0)
- ) # 1 TO 179 FOR BOTH
- tabWrite(
- "radius %.6f\n"
- % (
- (degrees(lamp.spot_size) / 2.0)
- * (1.0 - lamp.spot_blend)
- )
- )
-
- # Blender does not have a tightness equivalent, 0 is most like blender default.
- tabWrite("tightness 0\n") # 0:10f
-
- tabWrite("point_at <0, 0, -1>\n")
- if lamp.pov.use_halo:
- tabWrite("looks_like{\n")
- tabWrite("sphere{<0,0,0>,%.6f\n" % lamp.distance)
- tabWrite("hollow\n")
- tabWrite("material{\n")
- tabWrite("texture{\n")
- tabWrite(
- "pigment{rgbf<1,1,1,%.4f>}\n"
- % (lamp.pov.halo_intensity * 5.0)
- )
- tabWrite("}\n")
- tabWrite("interior{\n")
- tabWrite("media{\n")
- tabWrite("emission 1\n")
- tabWrite("scattering {1, 0.5}\n")
- tabWrite("density{\n")
- tabWrite("spherical\n")
- tabWrite("color_map{\n")
- tabWrite("[0.0 rgb <0,0,0>]\n")
- tabWrite("[0.5 rgb <1,1,1>]\n")
- tabWrite("[1.0 rgb <1,1,1>]\n")
- tabWrite("}\n")
- tabWrite("}\n")
- tabWrite("}\n")
- tabWrite("}\n")
- tabWrite("}\n")
- tabWrite("}\n")
- tabWrite("}\n")
- elif lamp.type == 'SUN':
- tabWrite("parallel\n")
- tabWrite("point_at <0, 0, -1>\n") # *must* be after 'parallel'
-
- elif lamp.type == 'AREA':
- tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
- # Area lights have no falloff type, so always use blenders lamp quad equivalent
- # for those?
- tabWrite("fade_power %d\n" % 2)
- size_x = lamp.size
- samples_x = lamp.pov.shadow_ray_samples_x
- if lamp.shape == 'SQUARE':
- size_y = size_x
- samples_y = samples_x
- else:
- size_y = lamp.size_y
- samples_y = lamp.pov.shadow_ray_samples_y
-
- tabWrite(
- "area_light <%.6f,0,0>,<0,%.6f,0> %d, %d\n"
- % (size_x, size_y, samples_x, samples_y)
- )
- tabWrite("area_illumination\n")
- if lamp.pov.shadow_ray_sample_method == 'CONSTANT_JITTERED':
- if lamp.pov.use_jitter:
- tabWrite("jitter\n")
- else:
- tabWrite("adaptive 1\n")
- tabWrite("jitter\n")
-
- # No shadow checked either at global or light level:
- if not scene.pov.use_shadows or (
- lamp.pov.shadow_method == 'NOSHADOW'
- ):
- tabWrite("shadowless\n")
-
- # Sun shouldn't be attenuated. Area lights have no falloff attribute so they
- # are put to type 2 attenuation a little higher above.
- if lamp.type not in {'SUN', 'AREA'}:
- if lamp.falloff_type == 'INVERSE_SQUARE':
- tabWrite(
- "fade_distance %.6f\n" % (sqrt(lamp.distance / 2.0))
- )
- tabWrite(
- "fade_power %d\n" % 2
- ) # Use blenders lamp quad equivalent
- elif lamp.falloff_type == 'INVERSE_LINEAR':
- tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
- tabWrite("fade_power %d\n" % 1) # Use blenders lamp linear
- elif lamp.falloff_type == 'CONSTANT':
- tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
- tabWrite("fade_power %d\n" % 3)
- # Use blenders lamp constant equivalent no attenuation.
- # Using Custom curve for fade power 3 for now.
- elif lamp.falloff_type == 'CUSTOM_CURVE':
- tabWrite("fade_power %d\n" % 4)
-
- writeMatrix(matrix)
-
- tabWrite("}\n")
-
- lampCount += 1
-
- # v(A,B) rotates vector A about origin by vector B.
- file.write(
- "#declare lampTarget%s= vrotate(<%.4g,%.4g,%.4g>,<%.4g,%.4g,%.4g>);\n"
- % (
- lampCount,
- -(ob.location.x),
- -(ob.location.y),
- -(ob.location.z),
- ob.rotation_euler.x,
- ob.rotation_euler.y,
- ob.rotation_euler.z,
- )
- )
-
- ####################################################################################################
- def exportRainbows(rainbows):
- """write all POV rainbows primitives to exported file """
- for ob in rainbows:
- povdataname = ob.data.name # enough?
- angle = degrees(ob.data.spot_size / 2.5) # radians in blender (2
- width = ob.data.spot_blend * 10
- distance = ob.data.shadow_buffer_clip_start
- # eps=0.0000001
- # angle = br/(cr+eps) * 10 #eps is small epsilon variable to avoid dividing by zero
- # width = ob.dimensions[2] #now let's say width of rainbow is the actual proxy height
- # formerly:
- # cz-bz # let's say width of the rainbow is height of the cone (interfacing choice
-
- # v(A,B) rotates vector A about origin by vector B.
- # and avoid a 0 length vector by adding 1
-
- # file.write("#declare %s_Target= vrotate(<%.6g,%.6g,%.6g>,<%.4g,%.4g,%.4g>);\n" % \
- # (povdataname, -(ob.location.x+0.1), -(ob.location.y+0.1), -(ob.location.z+0.1),
- # ob.rotation_euler.x, ob.rotation_euler.y, ob.rotation_euler.z))
-
- direction = (
- ob.location.x,
- ob.location.y,
- ob.location.z,
- ) # not taking matrix into account
- rmatrix = global_matrix @ ob.matrix_world
-
- # ob.rotation_euler.to_matrix().to_4x4() * mathutils.Vector((0,0,1))
- # XXX Is result of the below offset by 90 degrees?
- up = ob.matrix_world.to_3x3()[1].xyz # * global_matrix
-
- # XXX TO CHANGE:
- # formerly:
- # tabWrite("#declare %s = rainbow {\n"%povdataname)
-
- # clumsy for now but remove the rainbow from instancing
- # system because not an object. use lamps later instead of meshes
-
- # del data_ref[dataname]
- tabWrite("rainbow {\n")
-
- tabWrite("angle %.4f\n" % angle)
- tabWrite("width %.4f\n" % width)
- tabWrite("distance %.4f\n" % distance)
- tabWrite("arc_angle %.4f\n" % ob.pov.arc_angle)
- tabWrite("falloff_angle %.4f\n" % ob.pov.falloff_angle)
- tabWrite("direction <%.4f,%.4f,%.4f>\n" % rmatrix.translation[:])
- tabWrite("up <%.4f,%.4f,%.4f>\n" % (up[0], up[1], up[2]))
- tabWrite("color_map {\n")
- tabWrite("[0.000 color srgbt<1.0, 0.5, 1.0, 1.0>]\n")
- tabWrite("[0.130 color srgbt<0.5, 0.5, 1.0, 0.9>]\n")
- tabWrite("[0.298 color srgbt<0.2, 0.2, 1.0, 0.7>]\n")
- tabWrite("[0.412 color srgbt<0.2, 1.0, 1.0, 0.4>]\n")
- tabWrite("[0.526 color srgbt<0.2, 1.0, 0.2, 0.4>]\n")
- tabWrite("[0.640 color srgbt<1.0, 1.0, 0.2, 0.4>]\n")
- tabWrite("[0.754 color srgbt<1.0, 0.5, 0.2, 0.6>]\n")
- tabWrite("[0.900 color srgbt<1.0, 0.2, 0.2, 0.7>]\n")
- tabWrite("[1.000 color srgbt<1.0, 0.2, 0.2, 1.0>]\n")
- tabWrite("}\n")
-
- povMatName = "Default_texture"
- # tabWrite("texture {%s}\n"%povMatName)
- write_object_modifiers(scene, ob, file)
- # tabWrite("rotate x*90\n")
- # matrix = global_matrix @ ob.matrix_world
- # writeMatrix(matrix)
- tabWrite("}\n")
- # continue #Don't render proxy mesh, skip to next object
-
- ################################XXX LOFT, ETC.
- def exportCurves(scene, ob):
- """write all curves based POV primitives to exported file """
- name_orig = "OB" + ob.name
- dataname_orig = "DATA" + ob.data.name
-
- name = string_strip_hyphen(bpy.path.clean_name(name_orig))
- dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
-
- global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
- matrix = global_matrix @ ob.matrix_world
- bezier_sweep = False
- if ob.pov.curveshape == 'sphere_sweep':
- # inlined spheresweep macro, which itself calls Shapes.inc:
- file.write(' #include "shapes.inc"\n')
-
- file.write(
- ' #macro Shape_Bezierpoints_Sphere_Sweep(_merge_shape, _resolution, _points_array, _radius_array)\n'
- )
- file.write(' //input adjusting and inspection\n')
- file.write(' #if(_resolution <= 1)\n')
- file.write(' #local res = 1;\n')
- file.write(' #else\n')
- file.write(' #local res = int(_resolution);\n')
- file.write(' #end\n')
- file.write(
- ' #if(dimensions(_points_array) != 1 | dimensions(_radius_array) != 1)\n'
- )
- file.write(' #error ""\n')
- file.write(
- ' #elseif(div(dimension_size(_points_array,1),4) - dimension_size(_points_array,1)/4 != 0)\n'
- )
- file.write(' #error ""\n')
- file.write(
- ' #elseif(dimension_size(_points_array,1) != dimension_size(_radius_array,1))\n'
- )
- file.write(' #error ""\n')
- file.write(' #else\n')
- file.write(
- ' #local n_of_seg = div(dimension_size(_points_array,1), 4);\n'
- )
- file.write(' #local ctrl_pts_array = array[n_of_seg]\n')
- file.write(' #local ctrl_rs_array = array[n_of_seg]\n')
- file.write(' #for(i, 0, n_of_seg-1)\n')
- file.write(
- ' #local ctrl_pts_array[i] = array[4] {_points_array[4*i], _points_array[4*i+1], _points_array[4*i+2], _points_array[4*i+3]}\n'
- )
- file.write(
- ' #local ctrl_rs_array[i] = array[4] {abs(_radius_array[4*i]), abs(_radius_array[4*i+1]), abs(_radius_array[4*i+2]), abs(_radius_array[4*i+3])}\n'
- )
- file.write(' #end\n')
- file.write(' #end\n')
-
- file.write(' //drawing\n')
- file.write(' #local mockup1 =\n')
- file.write(' #if(_merge_shape) merge{ #else union{ #end\n')
- file.write(' #for(i, 0, n_of_seg-1)\n')
- file.write(' #local has_head = true;\n')
- file.write(' #if(i = 0)\n')
- file.write(
- ' #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[n_of_seg-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[n_of_seg-1][3] <= 0)\n'
- )
- file.write(' #local has_head = false;\n')
- file.write(' #end\n')
- file.write(' #else\n')
- file.write(
- ' #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[i-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[i-1][3] <= 0)\n'
- )
- file.write(' #local has_head = false;\n')
- file.write(' #end\n')
- file.write(' #end\n')
- file.write(' #if(has_head = true)\n')
- file.write(' sphere{\n')
- file.write(
- ' ctrl_pts_array[i][0], ctrl_rs_array[i][0]\n'
- )
- file.write(' }\n')
- file.write(' #end\n')
- file.write(' #local para_t = (1/2)/res;\n')
- file.write(
- ' #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
- )
- file.write(
- ' #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
- )
- file.write(
- ' #if(vlength(this_point-ctrl_pts_array[i][0]) > abs(this_radius-ctrl_rs_array[i][0]))\n'
- )
- file.write(' object{\n')
- file.write(
- ' Connect_Spheres(ctrl_pts_array[i][0], ctrl_rs_array[i][0], this_point, this_radius)\n'
- )
- file.write(' }\n')
- file.write(' #end\n')
- file.write(' sphere{\n')
- file.write(' this_point, this_radius\n')
- file.write(' }\n')
- file.write(' #for(j, 1, res-1)\n')
- file.write(' #local last_point = this_point;\n')
- file.write(
- ' #local last_radius = this_radius;\n'
- )
- file.write(' #local para_t = (1/2+j)/res;\n')
- file.write(
- ' #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
- )
- file.write(
- ' #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
- )
- file.write(
- ' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
- )
- file.write(' object{\n')
- file.write(
- ' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
- )
- file.write(' }\n')
- file.write(' #end\n')
- file.write(' sphere{\n')
- file.write(' this_point, this_radius\n')
- file.write(' }\n')
- file.write(' #end\n')
- file.write(' #local last_point = this_point;\n')
- file.write(' #local last_radius = this_radius;\n')
- file.write(
- ' #local this_point = ctrl_pts_array[i][3];\n'
- )
- file.write(
- ' #local this_radius = ctrl_rs_array[i][3];\n'
- )
- file.write(
- ' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
- )
- file.write(' object{\n')
- file.write(
- ' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
- )
- file.write(' }\n')
- file.write(' #end\n')
- file.write(' sphere{\n')
- file.write(' this_point, this_radius\n')
- file.write(' }\n')
- file.write(' #end\n')
- file.write(' }\n')
- file.write(' mockup1\n')
- file.write(' #end\n')
-
- for spl in ob.data.splines:
- if spl.type == "BEZIER":
- bezier_sweep = True
- if ob.pov.curveshape in {'loft', 'birail'}:
- n = 0
- for spline in ob.data.splines:
- n += 1
- tabWrite('#declare %s%s=spline {\n' % (dataname, n))
- tabWrite('cubic_spline\n')
- lp = len(spline.points)
- delta = 1 / (lp)
- d = -delta
- point = spline.points[lp - 1]
- x, y, z, w = point.co[:]
- tabWrite('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
- d += delta
- for point in spline.points:
- x, y, z, w = point.co[:]
- tabWrite('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
- d += delta
- for i in range(2):
- point = spline.points[i]
- x, y, z, w = point.co[:]
- tabWrite('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
- d += delta
- tabWrite('}\n')
- if ob.pov.curveshape in {'loft'}:
- n = len(ob.data.splines)
- tabWrite('#declare %s = array[%s]{\n' % (dataname, (n + 3)))
- tabWrite('spline{%s%s},\n' % (dataname, n))
- for i in range(n):
- tabWrite('spline{%s%s},\n' % (dataname, (i + 1)))
- tabWrite('spline{%s1},\n' % (dataname))
- tabWrite('spline{%s2}\n' % (dataname))
- tabWrite('}\n')
- # Use some of the Meshmaker.inc macro, here inlined
- file.write('#macro CheckFileName(FileName)\n')
- file.write(' #local Len=strlen(FileName);\n')
- file.write(' #if(Len>0)\n')
- file.write(' #if(file_exists(FileName))\n')
- file.write(' #if(Len>=4)\n')
- file.write(
- ' #local Ext=strlwr(substr(FileName,Len-3,4))\n'
- )
- file.write(
- ' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
- )
- file.write(' #local Return=99;\n')
- file.write(' #else\n')
- file.write(' #local Return=0;\n')
- file.write(' #end\n')
- file.write(' #else\n')
- file.write(' #local Return=0;\n')
- file.write(' #end\n')
- file.write(' #else\n')
- file.write(' #if(Len>=4)\n')
- file.write(
- ' #local Ext=strlwr(substr(FileName,Len-3,4))\n'
- )
- file.write(
- ' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
- )
- file.write(' #if (strcmp(Ext,".obj")=0)\n')
- file.write(' #local Return=2;\n')
- file.write(' #end\n')
- file.write(' #if (strcmp(Ext,".pcm")=0)\n')
- file.write(' #local Return=3;\n')
- file.write(' #end\n')
- file.write(' #if (strcmp(Ext,".arr")=0)\n')
- file.write(' #local Return=4;\n')
- file.write(' #end\n')
- file.write(' #else\n')
- file.write(' #local Return=1;\n')
- file.write(' #end\n')
- file.write(' #else\n')
- file.write(' #local Return=1;\n')
- file.write(' #end\n')
- file.write(' #end\n')
- file.write(' #else\n')
- file.write(' #local Return=1;\n')
- file.write(' #end\n')
- file.write(' (Return)\n')
- file.write('#end\n')
-
- file.write('#macro BuildSpline(Arr, SplType)\n')
- file.write(' #local Ds=dimension_size(Arr,1);\n')
- file.write(' #local Asc=asc(strupr(SplType));\n')
- file.write(' #if(Asc!=67 & Asc!=76 & Asc!=81) \n')
- file.write(' #local Asc=76;\n')
- file.write(
- ' #debug "\nWrong spline type defined (C/c/L/l/N/n/Q/q), using default linear_spline\\n"\n'
- )
- file.write(' #end\n')
- file.write(' spline {\n')
- file.write(' #switch (Asc)\n')
- file.write(' #case (67) //C cubic_spline\n')
- file.write(' cubic_spline\n')
- file.write(' #break\n')
- file.write(' #case (76) //L linear_spline\n')
- file.write(' linear_spline\n')
- file.write(' #break\n')
- file.write(' #case (78) //N linear_spline\n')
- file.write(' natural_spline\n')
- file.write(' #break\n')
- file.write(' #case (81) //Q Quadratic_spline\n')
- file.write(' quadratic_spline\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' #local Add=1/((Ds-2)-1);\n')
- file.write(' #local J=0-Add;\n')
- file.write(' #local I=0;\n')
- file.write(' #while (I<Ds)\n')
- file.write(' J\n')
- file.write(' Arr[I]\n')
- file.write(' #local I=I+1;\n')
- file.write(' #local J=J+Add;\n')
- file.write(' #end\n')
- file.write(' }\n')
- file.write('#end\n')
-
- file.write(
- '#macro BuildWriteMesh2(VecArr, NormArr, UVArr, U, V, FileName)\n'
- )
- # suppressed some file checking from original macro because no more separate files
- file.write(' #local Write=0;\n')
- file.write(
- ' #debug concat("\\n\\n Building mesh2: \\n - vertex_vectors\\n")\n'
- )
- file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
- file.write(' #switch (Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(' " vertex_vectors {\\n",\n')
- file.write(' " ", str(NumVertices,0,0),"\\n "\n')
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(' "# Vertices: ",str(NumVertices,0,0),"\\n"\n')
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(' str(2*NumVertices,0,0),",\\n"\n')
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "#declare VertexVectors= array[",str(NumVertices,0,0),"] {\\n "\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' mesh2 {\n')
- file.write(' vertex_vectors {\n')
- file.write(' NumVertices\n')
- file.write(' #local I=0;\n')
- file.write(' #while (I<NumVertices)\n')
- file.write(' VecArr[I]\n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(MeshFile, VecArr[I])\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "v ", VecArr[I].x," ", VecArr[I].y," ", VecArr[I].z,"\\n"\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' VecArr[I].x,",", VecArr[I].y,",", VecArr[I].z,",\\n"\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(MeshFile, VecArr[I])\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' #local I=I+1;\n')
- file.write(' #if(Write=1 | Write=4)\n')
- file.write(' #if(mod(I,3)=0)\n')
- file.write(' #write(MeshFile,"\\n ")\n')
- file.write(' #end\n')
- file.write(' #end \n')
- file.write(' #end\n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(MeshFile,"\\n }\\n")\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(MeshFile,"\\n")\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' // do nothing\n')
- file.write(' #break\n')
- file.write(' #case(4) \n')
- file.write(' #write(MeshFile,"\\n}\\n")\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' }\n')
-
- file.write(' #debug concat(" - normal_vectors\\n") \n')
- file.write(' #local NumVertices=dimension_size(NormArr,1);\n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(' " normal_vectors {\\n",\n')
- file.write(' " ", str(NumVertices,0,0),"\\n "\n')
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "# Normals: ",str(NumVertices,0,0),"\\n"\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' // do nothing\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "#declare NormalVectors= array[",str(NumVertices,0,0),"] {\\n "\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' normal_vectors {\n')
- file.write(' NumVertices\n')
- file.write(' #local I=0;\n')
- file.write(' #while (I<NumVertices)\n')
- file.write(' NormArr[I]\n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(MeshFile NormArr[I])\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "vn ", NormArr[I].x," ", NormArr[I].y," ", NormArr[I].z,"\\n"\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' NormArr[I].x,",", NormArr[I].y,",", NormArr[I].z,",\\n"\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(MeshFile NormArr[I])\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' #local I=I+1;\n')
- file.write(' #if(Write=1 | Write=4) \n')
- file.write(' #if(mod(I,3)=0)\n')
- file.write(' #write(MeshFile,"\\n ")\n')
- file.write(' #end\n')
- file.write(' #end\n')
- file.write(' #end\n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(MeshFile,"\\n }\\n")\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(MeshFile,"\\n")\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' //do nothing\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(MeshFile,"\\n}\\n")\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' }\n')
-
- file.write(' #debug concat(" - uv_vectors\\n") \n')
- file.write(' #local NumVertices=dimension_size(UVArr,1);\n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(\n')
- file.write(' MeshFile, \n')
- file.write(' " uv_vectors {\\n",\n')
- file.write(' " ", str(NumVertices,0,0),"\\n "\n')
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "# UV-vectors: ",str(NumVertices,0,0),"\\n"\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(
- ' // do nothing, *.pcm does not support uv-vectors\n'
- )
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "#declare UVVectors= array[",str(NumVertices,0,0),"] {\\n "\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' uv_vectors {\n')
- file.write(' NumVertices\n')
- file.write(' #local I=0;\n')
- file.write(' #while (I<NumVertices)\n')
- file.write(' UVArr[I]\n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(MeshFile UVArr[I])\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "vt ", UVArr[I].u," ", UVArr[I].v,"\\n"\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' //do nothing\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(MeshFile UVArr[I])\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' #local I=I+1; \n')
- file.write(' #if(Write=1 | Write=4)\n')
- file.write(' #if(mod(I,3)=0)\n')
- file.write(' #write(MeshFile,"\\n ")\n')
- file.write(' #end \n')
- file.write(' #end\n')
- file.write(' #end \n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(MeshFile,"\\n }\\n")\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(MeshFile,"\\n")\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' //do nothing\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(MeshFile,"\\n}\\n")\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' }\n')
- file.write('\n')
- file.write(' #debug concat(" - face_indices\\n") \n')
- file.write(' #declare NumFaces=U*V*2;\n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(' " face_indices {\\n"\n')
- file.write(' " ", str(NumFaces,0,0),"\\n "\n')
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write (\n')
- file.write(' MeshFile,\n')
- file.write(' "# faces: ",str(NumFaces,0,0),"\\n"\n')
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' #write (\n')
- file.write(' MeshFile,\n')
- file.write(' "0,",str(NumFaces,0,0),",\\n"\n')
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "#declare FaceIndices= array[",str(NumFaces,0,0),"] {\\n "\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' face_indices {\n')
- file.write(' NumFaces\n')
- file.write(' #local I=0;\n')
- file.write(' #local H=0;\n')
- file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
- file.write(' #while (I<V)\n')
- file.write(' #local J=0;\n')
- file.write(' #while (J<U)\n')
- file.write(' #local Ind=(I*U)+I+J;\n')
- file.write(
- ' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n'
- )
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' "f ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+1+1,"/",Ind+1+1,"/",Ind+1+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n",\n'
- )
- file.write(
- ' "f ",Ind+U+1+1,"/",Ind+U+1+1,"/",Ind+U+1+1," ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n"\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' Ind,",",Ind+NumVertices,",",Ind+1,",",Ind+1+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
- )
- file.write(
- ' Ind+U+1,",",Ind+U+1+NumVertices,",",Ind,",",Ind+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(\n')
- file.write(' MeshFile,\n')
- file.write(
- ' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n'
- )
- file.write(' )\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' #local J=J+1;\n')
- file.write(' #local H=H+1;\n')
- file.write(' #if(Write=1 | Write=4)\n')
- file.write(' #if(mod(H,3)=0)\n')
- file.write(' #write(MeshFile,"\\n ")\n')
- file.write(' #end \n')
- file.write(' #end\n')
- file.write(' #end\n')
- file.write(' #local I=I+1;\n')
- file.write(' #end\n')
- file.write(' }\n')
- file.write(' #switch(Write)\n')
- file.write(' #case(1)\n')
- file.write(' #write(MeshFile, "\\n }\\n}")\n')
- file.write(' #fclose MeshFile\n')
- file.write(' #debug concat(" Done writing\\n")\n')
- file.write(' #break\n')
- file.write(' #case(2)\n')
- file.write(' #fclose MeshFile\n')
- file.write(' #debug concat(" Done writing\\n")\n')
- file.write(' #break\n')
- file.write(' #case(3)\n')
- file.write(' #fclose MeshFile\n')
- file.write(' #debug concat(" Done writing\\n")\n')
- file.write(' #break\n')
- file.write(' #case(4)\n')
- file.write(' #write(MeshFile, "\\n}\\n}")\n')
- file.write(' #fclose MeshFile\n')
- file.write(' #debug concat(" Done writing\\n")\n')
- file.write(' #break\n')
- file.write(' #end\n')
- file.write(' }\n')
- file.write('#end\n')
-
- file.write(
- '#macro MSM(SplineArray, SplRes, Interp_type, InterpRes, FileName)\n'
- )
- file.write(' #declare Build=CheckFileName(FileName);\n')
- file.write(' #if(Build=0)\n')
- file.write(
- ' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n'
- )
- file.write(' #include FileName\n')
- file.write(' object{Surface}\n')
- file.write(' #else\n')
- file.write(' #local NumVertices=(SplRes+1)*(InterpRes+1);\n')
- file.write(' #local NumFaces=SplRes*InterpRes*2;\n')
- file.write(
- ' #debug concat("\\n Calculating ",str(NumVertices,0,0)," vertices for ", str(NumFaces,0,0)," triangles\\n\\n")\n'
- )
- file.write(' #local VecArr=array[NumVertices]\n')
- file.write(' #local NormArr=array[NumVertices]\n')
- file.write(' #local UVArr=array[NumVertices]\n')
- file.write(' #local N=dimension_size(SplineArray,1);\n')
- file.write(' #local TempSplArr0=array[N];\n')
- file.write(' #local TempSplArr1=array[N];\n')
- file.write(' #local TempSplArr2=array[N];\n')
- file.write(' #local PosStep=1/SplRes;\n')
- file.write(' #local InterpStep=1/InterpRes;\n')
- file.write(' #local Count=0;\n')
- file.write(' #local Pos=0;\n')
- file.write(' #while(Pos<=1)\n')
- file.write(' #local I=0;\n')
- file.write(' #if (Pos=0)\n')
- file.write(' #while (I<N)\n')
- file.write(
- ' #local Spl=spline{SplineArray[I]}\n'
- )
- file.write(
- ' #local TempSplArr0[I]=<0,0,0>+Spl(Pos);\n'
- )
- file.write(
- ' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n'
- )
- file.write(
- ' #local TempSplArr2[I]=<0,0,0>+Spl(Pos-PosStep);\n'
- )
- file.write(' #local I=I+1;\n')
- file.write(' #end\n')
- file.write(
- ' #local S0=BuildSpline(TempSplArr0, Interp_type)\n'
- )
- file.write(
- ' #local S1=BuildSpline(TempSplArr1, Interp_type)\n'
- )
- file.write(
- ' #local S2=BuildSpline(TempSplArr2, Interp_type)\n'
- )
- file.write(' #else\n')
- file.write(' #while (I<N)\n')
- file.write(
- ' #local Spl=spline{SplineArray[I]}\n'
- )
- file.write(
- ' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n'
- )
- file.write(' #local I=I+1;\n')
- file.write(' #end\n')
- file.write(
- ' #local S1=BuildSpline(TempSplArr1, Interp_type)\n'
- )
- file.write(' #end\n')
- file.write(' #local J=0;\n')
- file.write(' #while (J<=1)\n')
- file.write(' #local P0=<0,0,0>+S0(J);\n')
- file.write(' #local P1=<0,0,0>+S1(J);\n')
- file.write(' #local P2=<0,0,0>+S2(J);\n')
- file.write(' #local P3=<0,0,0>+S0(J+InterpStep);\n')
- file.write(' #local P4=<0,0,0>+S0(J-InterpStep);\n')
- file.write(' #local B1=P4-P0;\n')
- file.write(' #local B2=P2-P0;\n')
- file.write(' #local B3=P3-P0;\n')
- file.write(' #local B4=P1-P0;\n')
- file.write(' #local N1=vcross(B1,B2);\n')
- file.write(' #local N2=vcross(B2,B3);\n')
- file.write(' #local N3=vcross(B3,B4);\n')
- file.write(' #local N4=vcross(B4,B1);\n')
- file.write(
- ' #local Norm=vnormalize((N1+N2+N3+N4));\n'
- )
- file.write(' #local VecArr[Count]=P0;\n')
- file.write(' #local NormArr[Count]=Norm;\n')
- file.write(' #local UVArr[Count]=<J,Pos>;\n')
- file.write(' #local J=J+InterpStep;\n')
- file.write(' #local Count=Count+1;\n')
- file.write(' #end\n')
- file.write(' #local S2=spline{S0}\n')
- file.write(' #local S0=spline{S1}\n')
- file.write(
- ' #debug concat("\\r Done ", str(Count,0,0)," vertices : ", str(100*Count/NumVertices,0,2)," %")\n'
- )
- file.write(' #local Pos=Pos+PosStep;\n')
- file.write(' #end\n')
- file.write(
- ' BuildWriteMesh2(VecArr, NormArr, UVArr, InterpRes, SplRes, "")\n'
- )
- file.write(' #end\n')
- file.write('#end\n\n')
-
- file.write(
- '#macro Coons(Spl1, Spl2, Spl3, Spl4, Iter_U, Iter_V, FileName)\n'
- )
- file.write(' #declare Build=CheckFileName(FileName);\n')
- file.write(' #if(Build=0)\n')
- file.write(
- ' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n'
- )
- file.write(' #include FileName\n')
- file.write(' object{Surface}\n')
- file.write(' #else\n')
- file.write(' #local NumVertices=(Iter_U+1)*(Iter_V+1);\n')
- file.write(' #local NumFaces=Iter_U*Iter_V*2;\n')
- file.write(
- ' #debug concat("\\n Calculating ", str(NumVertices,0,0), " vertices for ",str(NumFaces,0,0), " triangles\\n\\n")\n'
- )
- file.write(' #declare VecArr=array[NumVertices] \n')
- file.write(' #declare NormArr=array[NumVertices] \n')
- file.write(' #local UVArr=array[NumVertices] \n')
- file.write(' #local Spl1_0=Spl1(0);\n')
- file.write(' #local Spl2_0=Spl2(0);\n')
- file.write(' #local Spl3_0=Spl3(0);\n')
- file.write(' #local Spl4_0=Spl4(0);\n')
- file.write(' #local UStep=1/Iter_U;\n')
- file.write(' #local VStep=1/Iter_V;\n')
- file.write(' #local Count=0;\n')
- file.write(' #local I=0;\n')
- file.write(' #while (I<=1)\n')
- file.write(' #local Im=1-I;\n')
- file.write(' #local J=0;\n')
- file.write(' #while (J<=1)\n')
- file.write(' #local Jm=1-J;\n')
- file.write(
- ' #local C0=Im*Jm*(Spl1_0)+Im*J*(Spl2_0)+I*J*(Spl3_0)+I*Jm*(Spl4_0);\n'
- )
- file.write(
- ' #local P0=LInterpolate(I, Spl1(J), Spl3(Jm)) + \n'
- )
- file.write(
- ' LInterpolate(Jm, Spl2(I), Spl4(Im))-C0;\n'
- )
- file.write(' #declare VecArr[Count]=P0;\n')
- file.write(' #local UVArr[Count]=<J,I>;\n')
- file.write(' #local J=J+UStep;\n')
- file.write(' #local Count=Count+1;\n')
- file.write(' #end\n')
- file.write(' #debug concat(\n')
- file.write(
- ' "\r Done ", str(Count,0,0)," vertices : ",\n'
- )
- file.write(' str(100*Count/NumVertices,0,2)," %"\n')
- file.write(' )\n')
- file.write(' #local I=I+VStep;\n')
- file.write(' #end\n')
- file.write(
- ' #debug "\r Normals "\n'
- )
- file.write(' #local Count=0;\n')
- file.write(' #local I=0;\n')
- file.write(' #while (I<=Iter_V)\n')
- file.write(' #local J=0;\n')
- file.write(' #while (J<=Iter_U)\n')
- file.write(' #local Ind=(I*Iter_U)+I+J;\n')
- file.write(' #local P0=VecArr[Ind];\n')
- file.write(' #if(J=0)\n')
- file.write(' #local P1=P0+(P0-VecArr[Ind+1]);\n')
- file.write(' #else\n')
- file.write(' #local P1=VecArr[Ind-1];\n')
- file.write(' #end\n')
- file.write(' #if (J=Iter_U)\n')
- file.write(' #local P2=P0+(P0-VecArr[Ind-1]);\n')
- file.write(' #else\n')
- file.write(' #local P2=VecArr[Ind+1];\n')
- file.write(' #end\n')
- file.write(' #if (I=0)\n')
- file.write(
- ' #local P3=P0+(P0-VecArr[Ind+Iter_U+1]);\n'
- )
- file.write(' #else\n')
- file.write(' #local P3=VecArr[Ind-Iter_U-1];\n')
- file.write(' #end\n')
- file.write(' #if (I=Iter_V)\n')
- file.write(
- ' #local P4=P0+(P0-VecArr[Ind-Iter_U-1]);\n'
- )
- file.write(' #else\n')
- file.write(' #local P4=VecArr[Ind+Iter_U+1];\n')
- file.write(' #end\n')
- file.write(' #local B1=P4-P0;\n')
- file.write(' #local B2=P2-P0;\n')
- file.write(' #local B3=P3-P0;\n')
- file.write(' #local B4=P1-P0;\n')
- file.write(' #local N1=vcross(B1,B2);\n')
- file.write(' #local N2=vcross(B2,B3);\n')
- file.write(' #local N3=vcross(B3,B4);\n')
- file.write(' #local N4=vcross(B4,B1);\n')
- file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
- file.write(' #declare NormArr[Count]=Norm;\n')
- file.write(' #local J=J+1;\n')
- file.write(' #local Count=Count+1;\n')
- file.write(' #end\n')
- file.write(
- ' #debug concat("\r Done ", str(Count,0,0)," normals : ",str(100*Count/NumVertices,0,2), " %")\n'
- )
- file.write(' #local I=I+1;\n')
- file.write(' #end\n')
- file.write(
- ' BuildWriteMesh2(VecArr, NormArr, UVArr, Iter_U, Iter_V, FileName)\n'
- )
- file.write(' #end\n')
- file.write('#end\n\n')
- # Empty curves
- if len(ob.data.splines) == 0:
- tabWrite("\n//dummy sphere to represent empty curve location\n")
- tabWrite("#declare %s =\n" % dataname)
- tabWrite(
- "sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
- % (ob.location.x, ob.location.y, ob.location.z)
- ) # ob.name > povdataname)
- # And non empty curves
- else:
- if bezier_sweep == False:
- tabWrite("#declare %s =\n" % dataname)
- if ob.pov.curveshape == 'sphere_sweep' and bezier_sweep == False:
- tabWrite("union {\n")
- for spl in ob.data.splines:
- if spl.type != "BEZIER":
- spl_type = "linear"
- if spl.type == "NURBS":
- spl_type = "cubic"
- points = spl.points
- numPoints = len(points)
- if spl.use_cyclic_u:
- numPoints += 3
-
- tabWrite(
- "sphere_sweep { %s_spline %s,\n"
- % (spl_type, numPoints)
- )
- if spl.use_cyclic_u:
- pt1 = points[len(points) - 1]
- wpt1 = pt1.co
- tabWrite(
- "<%.4g,%.4g,%.4g>,%.4g\n"
- % (
- wpt1[0],
- wpt1[1],
- wpt1[2],
- pt1.radius * ob.data.bevel_depth,
- )
- )
- for pt in points:
- wpt = pt.co
- tabWrite(
- "<%.4g,%.4g,%.4g>,%.4g\n"
- % (
- wpt[0],
- wpt[1],
- wpt[2],
- pt.radius * ob.data.bevel_depth,
- )
- )
- if spl.use_cyclic_u:
- for i in range(0, 2):
- endPt = points[i]
- wpt = endPt.co
- tabWrite(
- "<%.4g,%.4g,%.4g>,%.4g\n"
- % (
- wpt[0],
- wpt[1],
- wpt[2],
- endPt.radius * ob.data.bevel_depth,
- )
- )
-
- tabWrite("}\n")
- # below not used yet?
- if ob.pov.curveshape == 'sor':
- for spl in ob.data.splines:
- if spl.type in {'POLY', 'NURBS'}:
- points = spl.points
- numPoints = len(points)
- tabWrite("sor { %s,\n" % numPoints)
- for pt in points:
- wpt = pt.co
- tabWrite("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
- else:
- tabWrite("box { 0,0\n")
- if ob.pov.curveshape in {'lathe', 'prism'}:
- spl = ob.data.splines[0]
- if spl.type == "BEZIER":
- points = spl.bezier_points
- lenCur = len(points) - 1
- lenPts = lenCur * 4
- ifprism = ''
- if ob.pov.curveshape in {'prism'}:
- height = ob.data.extrude
- ifprism = '-%s, %s,' % (height, height)
- lenCur += 1
- lenPts += 4
- tabWrite(
- "%s { bezier_spline %s %s,\n"
- % (ob.pov.curveshape, ifprism, lenPts)
- )
- for i in range(0, lenCur):
- p1 = points[i].co
- pR = points[i].handle_right
- end = i + 1
- if i == lenCur - 1 and ob.pov.curveshape in {'prism'}:
- end = 0
- pL = points[end].handle_left
- p2 = points[end].co
- line = "<%.4g,%.4g>" % (p1[0], p1[1])
- line += "<%.4g,%.4g>" % (pR[0], pR[1])
- line += "<%.4g,%.4g>" % (pL[0], pL[1])
- line += "<%.4g,%.4g>" % (p2[0], p2[1])
- tabWrite("%s\n" % line)
- else:
- points = spl.points
- lenCur = len(points)
- lenPts = lenCur
- ifprism = ''
- if ob.pov.curveshape in {'prism'}:
- height = ob.data.extrude
- ifprism = '-%s, %s,' % (height, height)
- lenPts += 3
- spl_type = 'quadratic'
- if spl.type == 'POLY':
- spl_type = 'linear'
- tabWrite(
- "%s { %s_spline %s %s,\n"
- % (ob.pov.curveshape, spl_type, ifprism, lenPts)
- )
- if ob.pov.curveshape in {'prism'}:
- pt = points[len(points) - 1]
- wpt = pt.co
- tabWrite("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
- for pt in points:
- wpt = pt.co
- tabWrite("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
- if ob.pov.curveshape in {'prism'}:
- for i in range(2):
- pt = points[i]
- wpt = pt.co
- tabWrite("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
- if bezier_sweep:
- for p in range(len(ob.data.splines)):
- br = []
- depth = ob.data.bevel_depth
- spl = ob.data.splines[p]
- points = spl.bezier_points
- lenCur = len(points) - 1
- numPoints = lenCur * 4
- if spl.use_cyclic_u:
- lenCur += 1
- numPoints += 4
- tabWrite(
- "#declare %s_points_%s = array[%s]{\n"
- % (dataname, p, numPoints)
- )
- for i in range(lenCur):
- p1 = points[i].co
- pR = points[i].handle_right
- end = i + 1
- if spl.use_cyclic_u and i == (lenCur - 1):
- end = 0
- pL = points[end].handle_left
- p2 = points[end].co
- r3 = points[end].radius * depth
- r0 = points[i].radius * depth
- r1 = 2 / 3 * r0 + 1 / 3 * r3
- r2 = 1 / 3 * r0 + 2 / 3 * r3
- br.append((r0, r1, r2, r3))
- line = "<%.4g,%.4g,%.4f>" % (p1[0], p1[1], p1[2])
- line += "<%.4g,%.4g,%.4f>" % (pR[0], pR[1], pR[2])
- line += "<%.4g,%.4g,%.4f>" % (pL[0], pL[1], pL[2])
- line += "<%.4g,%.4g,%.4f>" % (p2[0], p2[1], p2[2])
- tabWrite("%s\n" % line)
- tabWrite("}\n")
- tabWrite(
- "#declare %s_radii_%s = array[%s]{\n"
- % (dataname, p, len(br) * 4)
- )
- for Tuple in br:
- tabWrite(
- '%.4f,%.4f,%.4f,%.4f\n'
- % (Tuple[0], Tuple[1], Tuple[2], Tuple[3])
- )
- tabWrite("}\n")
- if len(ob.data.splines) == 1:
- tabWrite('#declare %s = object{\n' % dataname)
- tabWrite(
- ' Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s) \n'
- % (ob.data.resolution_u, dataname, p, dataname, p)
- )
- else:
- tabWrite('#declare %s = union{\n' % dataname)
- for p in range(len(ob.data.splines)):
- tabWrite(
- ' object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s)} \n'
- % (ob.data.resolution_u, dataname, p, dataname, p)
- )
- # tabWrite('#include "bezier_spheresweep.inc"\n') #now inlined
- # tabWrite('#declare %s = object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_bezier_points, %.4f) \n'%(dataname,ob.data.resolution_u,dataname,ob.data.bevel_depth))
- if ob.pov.curveshape in {'loft'}:
- tabWrite(
- 'object {MSM(%s,%s,"c",%s,"")\n'
- % (dataname, ob.pov.res_u, ob.pov.res_v)
- )
- if ob.pov.curveshape in {'birail'}:
- splines = '%s1,%s2,%s3,%s4' % (
- dataname,
- dataname,
- dataname,
- dataname,
- )
- tabWrite(
- 'object {Coons(%s, %s, %s, "")\n'
- % (splines, ob.pov.res_u, ob.pov.res_v)
- )
- 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)
- if ob.pov.curveshape in {'prism'}:
- tabWrite("rotate <90,0,0>\n")
- tabWrite("scale y*-1\n")
- tabWrite("}\n")
-
#################################################################
- def exportMeta(metas):
+ def export_meta(metas):
"""write all POV blob primitives and Blender Metas to exported file """
# TODO - blenders 'motherball' naming is not supported.
@@ -2052,8 +324,7 @@ def write_pov(filename, scene=None, info_callback=None):
elems = [
(elem, ob)
for elem in ob.data.elements
- if elem.type
- in {'BALL', 'ELLIPSOID', 'CAPSULE', 'CUBE', 'PLANE'}
+ if elem.type in {'BALL', 'ELLIPSOID', 'CAPSULE', 'CUBE', 'PLANE'}
]
if prefix in meta_elems:
meta_elems[prefix].extend(elems)
@@ -2062,19 +333,16 @@ def write_pov(filename, scene=None, info_callback=None):
# empty metaball
if len(elems) == 0:
- tabWrite("\n//dummy sphere to represent empty meta location\n")
- tabWrite(
+ tab_write("\n//dummy sphere to represent empty meta location\n")
+ tab_write(
"sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
% (ob.location.x, ob.location.y, ob.location.z)
) # ob.name > povdataname)
# other metaballs
else:
- for mg, ob in meta_group.items():
+ for mg, mob in meta_group.items():
if len(meta_elems[mg]) != 0:
- tabWrite(
- "blob{threshold %.4g // %s \n"
- % (ob.data.threshold, mg)
- )
+ tab_write("blob{threshold %.4g // %s \n" % (mob.data.threshold, mg))
for elems in meta_elems[mg]:
elem = elems[0]
loc = elem.co
@@ -2082,22 +350,14 @@ def write_pov(filename, scene=None, info_callback=None):
if elem.use_negative:
stiffness = -stiffness
if elem.type == 'BALL':
- tabWrite(
+ tab_write(
"sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g "
- % (
- loc.x,
- loc.y,
- loc.z,
- elem.radius,
- stiffness,
- )
+ % (loc.x, loc.y, loc.z, elem.radius, stiffness)
)
- writeMatrix(
- global_matrix @ elems[1].matrix_world
- )
- tabWrite("}\n")
+ write_matrix(global_matrix @ elems[1].matrix_world)
+ tab_write("}\n")
elif elem.type == 'ELLIPSOID':
- tabWrite(
+ tab_write(
"sphere{ <%.6g, %.6g, %.6g>,%.4g,%.4g "
% (
loc.x / elem.size_x,
@@ -2107,16 +367,14 @@ def write_pov(filename, scene=None, info_callback=None):
stiffness,
)
)
- tabWrite(
+ tab_write(
"scale <%.6g, %.6g, %.6g>"
% (elem.size_x, elem.size_y, elem.size_z)
)
- writeMatrix(
- global_matrix @ elems[1].matrix_world
- )
- tabWrite("}\n")
+ write_matrix(global_matrix @ elems[1].matrix_world)
+ tab_write("}\n")
elif elem.type == 'CAPSULE':
- tabWrite(
+ tab_write(
"cylinder{ <%.6g, %.6g, %.6g>,<%.6g, %.6g, %.6g>,%.4g,%.4g "
% (
(loc.x - elem.size_x),
@@ -2129,14 +387,12 @@ def write_pov(filename, scene=None, info_callback=None):
stiffness,
)
)
- # tabWrite("scale <%.6g, %.6g, %.6g>" % (elem.size_x, elem.size_y, elem.size_z))
- writeMatrix(
- global_matrix @ elems[1].matrix_world
- )
- tabWrite("}\n")
+ # tab_write("scale <%.6g, %.6g, %.6g>" % (elem.size_x, elem.size_y, elem.size_z))
+ write_matrix(global_matrix @ elems[1].matrix_world)
+ tab_write("}\n")
elif elem.type == 'CUBE':
- tabWrite(
+ tab_write(
"cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1/4,1,1> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
@@ -2149,11 +405,9 @@ def write_pov(filename, scene=None, info_callback=None):
elem.size_z,
)
)
- writeMatrix(
- global_matrix @ elems[1].matrix_world
- )
- tabWrite("}\n")
- tabWrite(
+ write_matrix(global_matrix @ elems[1].matrix_world)
+ tab_write("}\n")
+ tab_write(
"cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
@@ -2166,11 +420,9 @@ def write_pov(filename, scene=None, info_callback=None):
elem.size_z,
)
)
- writeMatrix(
- global_matrix @ elems[1].matrix_world
- )
- tabWrite("}\n")
- tabWrite(
+ write_matrix(global_matrix @ elems[1].matrix_world)
+ tab_write("}\n")
+ tab_write(
"cylinder { -z*8, +z*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1,1/4> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
@@ -2183,13 +435,11 @@ def write_pov(filename, scene=None, info_callback=None):
elem.size_z,
)
)
- writeMatrix(
- global_matrix @ elems[1].matrix_world
- )
- tabWrite("}\n")
+ write_matrix(global_matrix @ elems[1].matrix_world)
+ tab_write("}\n")
elif elem.type == 'PLANE':
- tabWrite(
+ tab_write(
"cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1/4,1,1> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
@@ -2202,11 +452,9 @@ def write_pov(filename, scene=None, info_callback=None):
elem.size_z,
)
)
- writeMatrix(
- global_matrix @ elems[1].matrix_world
- )
- tabWrite("}\n")
- tabWrite(
+ write_matrix(global_matrix @ elems[1].matrix_world)
+ tab_write("}\n")
+ tab_write(
"cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
@@ -2219,16 +467,16 @@ def write_pov(filename, scene=None, info_callback=None):
elem.size_z,
)
)
- writeMatrix(
- global_matrix @ elems[1].matrix_world
- )
- tabWrite("}\n")
+ write_matrix(global_matrix @ elems[1].matrix_world)
+ tab_write("}\n")
try:
material = elems[1].data.materials[
0
] # lame! - blender cant do enything else.
- except:
+ except BaseException as e:
+ print(e.__doc__)
+ print('An exception occurred: {}'.format(e))
material = None
if material:
diffuse_color = material.diffuse_color
@@ -2237,40 +485,34 @@ def write_pov(filename, scene=None, info_callback=None):
material.use_transparency
and material.transparency_method == 'RAYTRACE'
):
- povFilter = (
- material.pov_raytrace_transparency.filter
- * (1.0 - material.alpha)
+ pov_filter = material.pov_raytrace_transparency.filter * (
+ 1.0 - material.alpha
)
- trans = (1.0 - material.pov.alpha) - povFilter
+ trans = (1.0 - material.pov.alpha) - pov_filter
else:
- povFilter = 0.0
- material_finish = materialNames[material.name]
- tabWrite(
+ pov_filter = 0.0
+ material_finish = material_names_dictionary[material.name]
+ tab_write(
"pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n"
% (
diffuse_color[0],
diffuse_color[1],
diffuse_color[2],
- povFilter,
+ pov_filter,
trans,
)
)
- tabWrite(
- "finish{%s} " % safety(material_finish, Level=2)
- )
+ tab_write("finish{%s} " % safety(material_finish, ref_level_bound=2))
else:
- tabWrite(
+ tab_write(
"pigment{srgb 1} finish{%s} "
- % (safety(DEF_MAT_NAME, Level=2))
+ % (safety(DEF_MAT_NAME, ref_level_bound=2))
)
- writeObjectMaterial(material, ob)
- # writeObjectMaterial(material, elems[1])
- tabWrite(
- "radiosity{importance %3g}\n"
- % ob.pov.importance_value
- )
- tabWrite("}\n\n") # End of Metaball block
+ write_object_material(material, mob, tab_write)
+ # write_object_material(material, elems[1])
+ tab_write("radiosity{importance %3g}\n" % mob.pov.importance_value)
+ tab_write("}\n\n") # End of Metaball block
'''
meta = ob.data
@@ -2279,8 +521,8 @@ def write_pov(filename, scene=None, info_callback=None):
elements = [elem for elem in meta.elements if elem.type in {'BALL', 'ELLIPSOID'}]
if elements:
- tabWrite("blob {\n")
- tabWrite("threshold %.4g\n" % meta.threshold)
+ tab_write("blob {\n")
+ tab_write("threshold %.4g\n" % meta.threshold)
importance = ob.pov.importance_value
try:
@@ -2297,7 +539,7 @@ def write_pov(filename, scene=None, info_callback=None):
if elem.type == 'BALL':
- tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
+ tab_write("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
(loc.x, loc.y, loc.z, elem.radius, stiffness))
# After this wecould do something simple like...
@@ -2306,2682 +548,137 @@ def write_pov(filename, scene=None, info_callback=None):
elif elem.type == 'ELLIPSOID':
# location is modified by scale
- tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
+ tab_write("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
(loc.x / elem.size_x,
loc.y / elem.size_y,
loc.z / elem.size_z,
elem.radius, stiffness))
- tabWrite("scale <%.6g, %.6g, %.6g> \n" %
+ tab_write("scale <%.6g, %.6g, %.6g> \n" %
(elem.size_x, elem.size_y, elem.size_z))
if material:
diffuse_color = material.diffuse_color
trans = 1.0 - material.pov.alpha
if material.use_transparency and material.transparency_method == 'RAYTRACE':
- povFilter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
- trans = (1.0 - material.pov.alpha) - povFilter
+ pov_filter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
+ trans = (1.0 - material.pov.alpha) - pov_filter
else:
- povFilter = 0.0
+ pov_filter = 0.0
- material_finish = materialNames[material.name]
+ material_finish = material_names_dictionary[material.name]
- tabWrite("pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" %
+ tab_write("pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" %
(diffuse_color[0], diffuse_color[1], diffuse_color[2],
- povFilter, trans))
- tabWrite("finish {%s}\n" % safety(material_finish, Level=2))
+ pov_filter, trans))
+ tab_write("finish {%s}\n" % safety(material_finish, ref_level_bound=2))
else:
- tabWrite("pigment {srgb 1} \n")
+ tab_write("pigment {srgb 1} \n")
# Write the finish last.
- tabWrite("finish {%s}\n" % (safety(DEF_MAT_NAME, Level=2)))
+ tab_write("finish {%s}\n" % (safety(DEF_MAT_NAME, ref_level_bound=2)))
- writeObjectMaterial(material, elems[1])
+ write_object_material(material, elems[1])
- writeMatrix(global_matrix @ ob.matrix_world)
+ write_matrix(global_matrix @ ob.matrix_world)
# Importance for radiosity sampling added here
- tabWrite("radiosity { \n")
+ tab_write("radiosity { \n")
# importance > ob.pov.importance_value
- tabWrite("importance %3g \n" % importance)
- tabWrite("}\n")
+ tab_write("importance %3g \n" % importance)
+ tab_write("}\n")
- tabWrite("}\n") # End of Metaball block
+ tab_write("}\n") # End of Metaball block
if comments and len(metas) >= 1:
file.write("\n")
'''
- # objectNames = {}
- DEF_OBJ_NAME = "Default"
-
- def exportMeshes(scene, sel, csg):
- """write all meshes as POV mesh2{} syntax to exported file """
- #some numpy functions to speed up mesh export
-
- # TODO: also write a numpy function to read matrices at object level?
- # feed below with mesh object.data, but only after doing data.calc_loop_triangles()
- def read_verts_co(self, mesh):
- #'float64' would be a slower 64-bit floating-point number numpy datatype
- # using 'float32' vert coordinates for now until any issue is reported
- mverts_co = np.zeros((len(mesh.vertices)*3), dtype=np.float32)
- mesh.vertices.foreach_get("co", mverts_co)
- return np.reshape(mverts_co, (len(mesh.vertices), 3))
-
- def read_verts_idx(self, mesh):
- mverts_idx = np.zeros((len(mesh.vertices)), dtype=np.int64)
- mesh.vertices.foreach_get("index", mverts_idx)
- return np.reshape(mverts_idx, (len(mesh.vertices), 1))
-
- def read_verts_norms(self, mesh):
- #'float64' would be a slower 64-bit floating-point number numpy datatype
- # using less accurate 'float16' normals for now until any issue is reported
- mverts_no = np.zeros((len(mesh.vertices)*3), dtype=np.float16)
- mesh.vertices.foreach_get("normal", mverts_no)
- return np.reshape(mverts_no, (len(mesh.vertices), 3))
-
- def read_faces_idx(self, mesh):
- mfaces_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int64)
- mesh.loop_triangles.foreach_get("index", mfaces_idx)
- return np.reshape(mfaces_idx, (len(mesh.loop_triangles), 1))
-
- def read_faces_verts_indices(self, mesh):
- mfaces_verts_idx = np.zeros((len(mesh.loop_triangles)*3), dtype=np.int64)
- mesh.loop_triangles.foreach_get("vertices", mfaces_verts_idx)
- return np.reshape(mfaces_verts_idx, (len(mesh.loop_triangles), 3))
-
- #Why is below different from verex indices?
- def read_faces_verts_loops(self, mesh):
- mfaces_verts_loops = np.zeros((len(mesh.loop_triangles)*3), dtype=np.int64)
- mesh.loop_triangles.foreach_get("loops", mfaces_verts_loops)
- return np.reshape(mfaces_verts_loops, (len(mesh.loop_triangles), 3))
-
- def read_faces_norms(self, mesh):
- #'float64' would be a slower 64-bit floating-point number numpy datatype
- # using less accurate 'float16' normals for now until any issue is reported
- mfaces_no = np.zeros((len(mesh.loop_triangles)*3), dtype=np.float16)
- mesh.loop_triangles.foreach_get("normal", mfaces_no)
- return np.reshape(mfaces_no, (len(mesh.loop_triangles), 3))
-
- def read_faces_smooth(self, mesh):
- mfaces_smth = np.zeros((len(mesh.loop_triangles)*1), dtype=np.bool)
- mesh.loop_triangles.foreach_get("use_smooth", mfaces_smth)
- return np.reshape(mfaces_smth, (len(mesh.loop_triangles), 1))
-
- def read_faces_material_indices(self, mesh):
- mfaces_mats_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int16)
- mesh.loop_triangles.foreach_get("material_index", mfaces_mats_idx)
- return np.reshape(mfaces_mats_idx, (len(mesh.loop_triangles), 1))
-
-
-
- # obmatslist = []
- # def hasUniqueMaterial():
- # # Grab materials attached to object instances ...
- # if hasattr(ob, 'material_slots'):
- # for ms in ob.material_slots:
- # if ms.material is not None and ms.link == 'OBJECT':
- # if ms.material in obmatslist:
- # return False
- # else:
- # obmatslist.append(ms.material)
- # return True
- # def hasObjectMaterial(ob):
- # # Grab materials attached to object instances ...
- # if hasattr(ob, 'material_slots'):
- # for ms in ob.material_slots:
- # if ms.material is not None and ms.link == 'OBJECT':
- # # If there is at least one material slot linked to the object
- # # and not the data (mesh), always create a new, "private" data instance.
- # return True
- # return False
- # For objects using local material(s) only!
- # This is a mapping between a tuple (dataname, materialnames, ...), and the POV dataname.
- # As only objects using:
- # * The same data.
- # * EXACTLY the same materials, in EXACTLY the same sockets.
- # ... can share a same instance in POV export.
- obmats2data = {}
-
- def checkObjectMaterials(ob, name, dataname):
- if hasattr(ob, 'material_slots'):
- has_local_mats = False
- key = [dataname]
- for ms in ob.material_slots:
- if ms.material is not None:
- key.append(ms.material.name)
- if ms.link == 'OBJECT' and not has_local_mats:
- has_local_mats = True
- else:
- # Even if the slot is empty, it is important to grab it...
- key.append("")
- if has_local_mats:
- # If this object uses local material(s), lets find if another object
- # using the same data and exactly the same list of materials
- # (in the same slots) has already been processed...
- # Note that here also, we use object name as new, unique dataname for Pov.
- key = tuple(key) # Lists are not hashable...
- if key not in obmats2data:
- obmats2data[key] = name
- return obmats2data[key]
- return None
-
- data_ref = {}
-
- def store(scene, ob, name, dataname, matrix):
- # The Object needs to be written at least once but if its data is
- # already in data_ref this has already been done.
- # This func returns the "povray" name of the data, or None
- # if no writing is needed.
- if ob.is_modified(scene, 'RENDER'):
- # Data modified.
- # Create unique entry in data_ref by using object name
- # (always unique in Blender) as data name.
- data_ref[name] = [(name, MatrixAsPovString(matrix))]
- return name
- # Here, we replace dataname by the value returned by checkObjectMaterials, only if
- # it is not evaluated to False (i.e. only if the object uses some local material(s)).
- dataname = checkObjectMaterials(ob, name, dataname) or dataname
- if dataname in data_ref:
- # Data already known, just add the object instance.
- data_ref[dataname].append((name, MatrixAsPovString(matrix)))
- # No need to write data
- return None
- else:
- # Data not yet processed, create a new entry in data_ref.
- data_ref[dataname] = [(name, MatrixAsPovString(matrix))]
- return dataname
-
- def exportSmoke(smoke_obj_name):
- # if LuxManager.CurrentScene.name == 'preview':
- # return 1, 1, 1, 1.0
- # else:
- flowtype = -1
- smoke_obj = bpy.data.objects[smoke_obj_name]
- domain = None
-
- # Search smoke domain target for smoke modifiers
- for mod in smoke_obj.modifiers:
- if mod.name == 'Smoke':
- if mod.smoke_type == 'FLOW':
- if mod.flow_settings.smoke_flow_type == 'BOTH':
- flowtype = 2
- else:
- if mod.flow_settings.smoke_flow_type == 'SMOKE':
- flowtype = 0
- else:
- if mod.flow_settings.smoke_flow_type == 'FIRE':
- flowtype = 1
-
- if mod.smoke_type == 'DOMAIN':
- domain = smoke_obj
- smoke_modifier = mod
-
- eps = 0.000001
- if domain is not None:
- # if bpy.app.version[0] >= 2 and bpy.app.version[1] >= 71:
- # Blender version 2.71 supports direct access to smoke data structure
- set = mod.domain_settings
- channeldata = []
- for v in set.density_grid:
- channeldata.append(v.real)
- print(v.real)
- ## Usage en voxel texture:
- # channeldata = []
- # if channel == 'density':
- # for v in set.density_grid:
- # channeldata.append(v.real)
-
- # if channel == 'fire':
- # for v in set.flame_grid:
- # channeldata.append(v.real)
-
- resolution = set.resolution_max
- big_res = []
- big_res.append(set.domain_resolution[0])
- big_res.append(set.domain_resolution[1])
- big_res.append(set.domain_resolution[2])
-
- if set.use_high_resolution:
- big_res[0] = big_res[0] * (set.amplify + 1)
- big_res[1] = big_res[1] * (set.amplify + 1)
- big_res[2] = big_res[2] * (set.amplify + 1)
- # else:
- # p = []
- ##gather smoke domain settings
- # BBox = domain.bound_box
- # p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
- # p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
- # set = mod.domain_settings
- # resolution = set.resolution_max
- # smokecache = set.point_cache
- # ret = read_cache(smokecache, set.use_high_resolution, set.amplify + 1, flowtype)
- # res_x = ret[0]
- # res_y = ret[1]
- # res_z = ret[2]
- # density = ret[3]
- # fire = ret[4]
-
- # if res_x * res_y * res_z > 0:
- ##new cache format
- # big_res = []
- # big_res.append(res_x)
- # big_res.append(res_y)
- # big_res.append(res_z)
- # else:
- # max = domain.dimensions[0]
- # if (max - domain.dimensions[1]) < -eps:
- # max = domain.dimensions[1]
-
- # if (max - domain.dimensions[2]) < -eps:
- # max = domain.dimensions[2]
-
- # big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
- # int(round(resolution * domain.dimensions[1] / max, 0)),
- # int(round(resolution * domain.dimensions[2] / max, 0))]
-
- # if set.use_high_resolution:
- # big_res = [big_res[0] * (set.amplify + 1), big_res[1] * (set.amplify + 1),
- # big_res[2] * (set.amplify + 1)]
-
- # if channel == 'density':
- # channeldata = density
-
- # if channel == 'fire':
- # channeldata = fire
-
- # sc_fr = '%s/%s/%s/%05d' % (efutil.export_path, efutil.scene_filename(), bpy.context.scene.name, bpy.context.scene.frame_current)
- # if not os.path.exists( sc_fr ):
- # os.makedirs(sc_fr)
- #
- # smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
- # smoke_path = '/'.join([sc_fr, smoke_filename])
- #
- # with open(smoke_path, 'wb') as smoke_file:
- # # Binary densitygrid file format
- # #
- # # File header
- # smoke_file.write(b'SMOKE') #magic number
- # smoke_file.write(struct.pack('<I', big_res[0]))
- # smoke_file.write(struct.pack('<I', big_res[1]))
- # smoke_file.write(struct.pack('<I', big_res[2]))
- # Density data
- # smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
- #
- # LuxLog('Binary SMOKE file written: %s' % (smoke_path))
-
- # return big_res[0], big_res[1], big_res[2], channeldata
-
- mydf3 = df3.df3(big_res[0], big_res[1], big_res[2])
- sim_sizeX, sim_sizeY, sim_sizeZ = mydf3.size()
- for x in range(sim_sizeX):
- for y in range(sim_sizeY):
- for z in range(sim_sizeZ):
- mydf3.set(
- x,
- y,
- z,
- channeldata[
- ((z * sim_sizeY + y) * sim_sizeX + x)
- ],
- )
-
- mydf3.exportDF3(smokePath)
- print('Binary smoke.df3 file written in preview directory')
- if comments:
- file.write("\n//--Smoke--\n\n")
-
- # Note: We start with a default unit cube.
- # This is mandatory to read correctly df3 data - otherwise we could just directly use bbox
- # coordinates from the start, and avoid scale/translate operations at the end...
- file.write("box{<0,0,0>, <1,1,1>\n")
- file.write(" pigment{ rgbt 1 }\n")
- file.write(" hollow\n")
- file.write(" interior{ //---------------------\n")
- file.write(" media{ method 3\n")
- file.write(
- " emission <1,1,1>*1\n"
- ) # 0>1 for dark smoke to white vapour
- file.write(" scattering{ 1, // Type\n")
- file.write(" <1,1,1>*0.1\n")
- file.write(" } // end scattering\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("}\n")
-
- # file.write(" interpolate 1\n")
- # file.write(" frequency 0\n")
- # file.write(" }\n")
- # file.write("}\n")
-
- ob_num = 0
- for ob in sel:
- # 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:
- renderEmitter = True
- 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
- #XXX Todo: replace by pov_(Particles?)_texture_slot
- 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,
- # it's automatic now.
- 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
- else:
- file.write('linear_spline ')
- file.write('%i,\n' % (steps))
- # changing world coordinates to object local coordinates by multiplying with inverted matrix
- initCo = ob.matrix_world.inverted() @ (
- pSys.co_hair(
- ob, particle_no=pindex, step=0
- )
- )
- if (
- ob.material_slots[
- pSys.settings.material - 1
- ].material
- and ob.active_material is not None
- ):
- pmaterial = ob.material_slots[
- pSys.settings.material - 1
- ].material
- for th in pmaterial.texture_slots:
- if (
- th
- and th.use
- and th.use_map_color_diffuse
- ):
- # treat POV textures as bitmaps
- if (
- th.texture.type
- == 'IMAGE'
- and th.texture.image
- and th.texture_coords
- == 'UV'
- and ob.data.uv_textures
- is not None
- ): # or (th.texture.pov.tex_pattern_type != 'emulator' and th.texture_coords == 'UV' and ob.data.uv_textures is not None):
- image = th.texture.image
- image_width = image.size[
- 0
- ]
- image_height = image.size[
- 1
- ]
- image_pixels = image.pixels[
- :
- ]
- uv_co = pSys.uv_on_emitter(
- mod,
- pSys.particles[
- pindex
- ],
- pindex,
- 0,
- )
- x_co = round(
- uv_co[0]
- * (image_width - 1)
- )
- y_co = round(
- uv_co[1]
- * (image_height - 1)
- )
- pixelnumber = (
- image_width * y_co
- ) + x_co
- r = image_pixels[
- pixelnumber * 4
- ]
- g = image_pixels[
- pixelnumber * 4 + 1
- ]
- b = image_pixels[
- pixelnumber * 4 + 2
- ]
- a = image_pixels[
- pixelnumber * 4 + 3
- ]
- initColor = (r, g, b, a)
- else:
- # only overwrite variable for each competing texture for now
- initColor = th.texture.evaluate(
- (
- initCo[0],
- initCo[1],
- initCo[2],
- )
- )
- for step in range(0, steps):
- co = ob.matrix_world.inverted() @ (
- pSys.co_hair(
- ob,
- particle_no=pindex,
- step=step,
- )
- )
- # for controlPoint in particle.hair_keys:
- if pSys.settings.clump_factor != 0:
- hDiameter = (
- pSys.settings.clump_factor
- / 200.0
- * random.uniform(0.5, 1)
- )
- elif step == 0:
- hDiameter = strandStart
- 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:
- file.write('\n')
-
- # End the array declaration.
-
- file.write('}\n')
- file.write('\n')
-
- 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,
- # it's automatic now.
- 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:
- 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
- else:
- 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
-
- 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
-
- 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
-
- 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
-
- 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
-
- 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,
- )
- )
- # Previous to 3.8 default max_gradient 1.0 was too slow
- tabWrite("max_gradient 0.001\n")
- 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[:]
- ## numpytest
- #me_looptris = me.loops
-
- ## otypes = ['int32'] is a 32-bit signed integer number numpy datatype
- #get_v_index = np.vectorize(lambda l: l.vertex_index, otypes = ['int32'], cache = True)
- #faces_verts_idx = get_v_index(me_looptris)
-
-
- # 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
- else:
- uv_layer = None
-
- 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
- for v in me.vertices:
- if linebreaksinlists:
- file.write(",\n")
- file.write(
- tabStr + "<%.6f, %.6f, %.6f>" % v.co[:]
- ) # vert count
- else:
- file.write(", ")
- 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
- else:
- 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)
- else:
- file.write(", ")
- file.write("<%.6f, %.6f>" % uv)
- index[0] = idx
- idx += 1
- '''
- else:
- # 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")
-
- 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
- else:
- 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
- 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]
-
- 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
- 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:
- file.write(", ")
- file.write(
- "<%d,%d,%d>"
- % (
- uniqueUVs[uvs[0]][0],
- uniqueUVs[uvs[1]][0],
- uniqueUVs[uvs[2]][0],
- )
- )
-
- file.write("\n")
- tabWrite("}\n")
-
- # XXX BOOLEAN
- onceCSG = 0
- for mod in ob.modifiers:
- if onceCSG == 0:
- if mod:
- if mod.type == 'BOOLEAN':
- if ob.pov.boolean_mod == "POV":
- file.write(
- "\tinside_vector <%.6g, %.6g, %.6g>\n"
- % (
- ob.pov.inside_vector[0],
- ob.pov.inside_vector[1],
- ob.pov.inside_vector[2],
- )
- )
- onceCSG = 1
-
- if me.materials:
- try:
- material = me.materials[0] # dodgy
- writeObjectMaterial(material, ob)
- except IndexError:
- print(me)
-
- # POV object modifiers such as
- # hollow / sturm / double_illuminate etc.
- write_object_modifiers(scene, ob, file)
-
- # Importance for radiosity sampling added here:
- tabWrite("radiosity { \n")
- tabWrite("importance %3g \n" % importance)
- tabWrite("}\n")
-
- tabWrite("}\n") # End of mesh block
- else:
- facesMaterials = [] # WARNING!!!!!!!!!!!!!!!!!!!!!!
- if me_materials:
- for f in me_faces:
- if f.material_index not in facesMaterials:
- facesMaterials.append(f.material_index)
- # No vertex colors, so write material colors as vertex colors
- for i, material in enumerate(me_materials):
-
- if (
- material
- and material.pov.material_use_nodes == False
- ): # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- # 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],
- i,
- ) # i == f.mat
- vertCols[key] = [-1]
- else:
- diffuse_color = material.diffuse_color[
- :
- ]
- key = (
- diffuse_color[0],
- diffuse_color[1],
- diffuse_color[2],
- i,
- ) # i == f.mat
- vertCols[key] = [-1]
-
- idx = 0
- LocalMaterialNames = []
- for col, index in vertCols.items():
- # if me_materials:
- mater = me_materials[col[3]]
- if me_materials is None: # XXX working?
- material_finish = (
- DEF_MAT_NAME
- ) # not working properly,
- trans = 0.0
-
- else:
- shading.writeTextureInfluence(
- using_uberpov,
- mater,
- materialNames,
- LocalMaterialNames,
- path_image,
- lampCount,
- imageFormat,
- imgMap,
- imgMapTransforms,
- tabWrite,
- comments,
- string_strip_hyphen,
- safety,
- col,
- os,
- preview_dir,
- unpacked_images,
- )
- ###################################################################
- index[0] = idx
- idx += 1
-
- # Vert Colors
- tabWrite("texture_list {\n")
- # In case there's is no material slot, give at least one texture
- # (an empty one so it uses pov default)
- if len(vertCols) == 0:
- file.write(tabStr + "1")
- else:
- file.write(
- tabStr + "%s" % (len(vertCols))
- ) # vert count
-
- # below "material" alias, added check ob.active_material
- # to avoid variable referenced before assignment error
- try:
- material = ob.active_material
- except IndexError:
- # when no material slot exists,
- material = None
-
- # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- if (
- material
- and ob.active_material is not None
- and material.pov.material_use_nodes == False
- ):
- if material.pov.replacement_text != "":
- file.write("\n")
- file.write(
- " texture{%s}\n"
- % material.pov.replacement_text
- )
-
- else:
- # Loop through declared materials list
- for cMN in LocalMaterialNames:
- if material != "Default":
- file.write(
- "\n texture{MAT_%s}\n" % cMN
- )
- # use string_strip_hyphen(materialNames[material]))
- # or Something like that to clean up the above?
- elif material and material.pov.material_use_nodes:
- for index in facesMaterials:
- faceMaterial = string_strip_hyphen(
- bpy.path.clean_name(
- me_materials[index].name
- )
- )
- file.write(
- "\n texture{%s}\n" % faceMaterial
- )
- # END!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- else:
- file.write(" texture{}\n")
- tabWrite("}\n")
-
- # Face indices
- tabWrite("face_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
- else:
- material = me_materials[material_index]
- ci1 = ci2 = ci3 = f.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]
-
- 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]
- elif material.pov.material_use_nodes:
- ci1 = ci2 = ci3 = 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]
-
- if linebreaksinlists:
- file.write(",\n")
- file.write(
- tabStr
- + "<%d,%d,%d>, %d,%d,%d"
- % (
- fv[0],
- fv[1],
- fv[2],
- ci1,
- ci2,
- ci3,
- )
- ) # vert count
- else:
- file.write(", ")
- file.write(
- "<%d,%d,%d>, %d,%d,%d"
- % (
- fv[0],
- fv[1],
- fv[2],
- ci1,
- ci2,
- ci3,
- )
- ) # 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
- else:
- idx = uniqueNormals[faces_normals[fi]][0]
- if linebreaksinlists:
- file.write(",\n")
- file.write(
- tabStr
- + "<%d,%d,%d>" % (idx, idx, idx)
- ) # vertcount
- 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:
- file.write(", ")
- file.write(
- "<%d,%d,%d>"
- % (
- uniqueUVs[uvs[0]][0],
- uniqueUVs[uvs[1]][0],
- uniqueUVs[uvs[2]][0],
- )
- )
-
- file.write("\n")
- tabWrite("}\n")
-
- # XXX BOOLEAN
- onceCSG = 0
- for mod in ob.modifiers:
- if onceCSG == 0:
- if mod:
- if mod.type == 'BOOLEAN':
- if ob.pov.boolean_mod == "POV":
- file.write(
- "\tinside_vector <%.6g, %.6g, %.6g>\n"
- % (
- ob.pov.inside_vector[0],
- ob.pov.inside_vector[1],
- ob.pov.inside_vector[2],
- )
- )
- onceCSG = 1
-
- if me.materials:
- try:
- material = me.materials[0] # dodgy
- writeObjectMaterial(material, ob)
- except IndexError:
- print(me)
-
- # POV object modifiers such as
- # hollow / sturm / double_illuminate etc.
- write_object_modifiers(scene, ob, file)
-
- # Importance for radiosity sampling added here:
- tabWrite("radiosity { \n")
- tabWrite("importance %3g \n" % importance)
- tabWrite("}\n")
-
- tabWrite("}\n") # End of mesh block
-
- ob_eval.to_mesh_clear()
-
- if csg:
- duplidata_ref = []
- _dupnames_seen = (
- dict()
- ) # avoid duplicate output during introspection
- for ob in sel:
- # matrix = global_matrix @ ob.matrix_world
- if ob.is_instancer:
- tabWrite("\n//--DupliObjects in %s--\n\n" % ob.name)
- # ob.dupli_list_create(scene) #deprecated in 2.8
- depsgraph = bpy.context.evaluated_depsgraph_get()
- dup = ""
- if ob.is_modified(scene, 'RENDER'):
- # modified object always unique so using object name rather than data name
- dup = "#declare OB%s = union{\n" % (
- string_strip_hyphen(bpy.path.clean_name(ob.name))
- )
- else:
- dup = "#declare DATA%s = union{\n" % (
- string_strip_hyphen(bpy.path.clean_name(ob.name))
- )
- for eachduplicate in depsgraph.object_instances:
- if (
- eachduplicate.is_instance
- ): # Real dupli instance filtered because original included in list since 2.8
- _dupname = eachduplicate.object.name
- _dupobj = bpy.data.objects[_dupname]
- # BEGIN introspection for troubleshooting purposes
- if not "name" in dir(_dupobj.data):
- if _dupname not in _dupnames_seen:
- print(
- "WARNING: bpy.data.objects[%s].data (of type %s) has no 'name' attribute"
- % (_dupname, type(_dupobj.data))
- )
- for _thing in dir(_dupobj):
- print(
- "|| %s.%s = %s"
- % (
- _dupname,
- _thing,
- getattr(_dupobj, _thing),
- )
- )
- _dupnames_seen[_dupname] = 1
- print(
- "''=> Unparseable objects so far: %s"
- % (_dupnames_seen)
- )
- else:
- _dupnames_seen[_dupname] += 1
- continue # don't try to parse data objects with no name attribute
- # END introspection for troubleshooting purposes
- duplidataname = "OB" + string_strip_hyphen(
- bpy.path.clean_name(_dupobj.data.name)
- )
- dupmatrix = (
- eachduplicate.matrix_world.copy()
- ) # has to be copied to not store instance since 2.8
- dup += "\tobject {\n\t\tDATA%s\n\t\t%s\t}\n" % (
- string_strip_hyphen(
- bpy.path.clean_name(_dupobj.data.name)
- ),
- MatrixAsPovString(
- ob.matrix_world.inverted() @ dupmatrix
- ),
- )
- # add object to a list so that it is not rendered for some instance_types
- if (
- ob.instance_type not in {'COLLECTION'}
- and duplidataname not in duplidata_ref
- ):
- duplidata_ref.append(
- duplidataname
- ) # older key [string_strip_hyphen(bpy.path.clean_name("OB"+ob.name))]
- dup += "}\n"
- # ob.dupli_list_clear()# just do not store any reference to instance since 2.8
- tabWrite(dup)
- else:
- continue
- print(
- "WARNING: Unparseable objects in current .blend file:\n''=> %s"
- % (_dupnames_seen)
- )
- print("duplidata_ref = %s" % (duplidata_ref))
- for data_name, inst in data_ref.items():
- for ob_name, matrix_str in inst:
- if (
- ob_name not in duplidata_ref
- ): # .items() for a dictionary
- tabWrite(
- "\n//----Blender Object Name:%s----\n" % ob_name
- )
- if ob.pov.object_as == '':
- tabWrite("object { \n")
- tabWrite("%s\n" % data_name)
- tabWrite("%s\n" % matrix_str)
- tabWrite("}\n")
- else:
- no_boolean = True
- for mod in ob.modifiers:
- if mod.type == 'BOOLEAN':
- operation = None
- no_boolean = False
- if mod.operation == 'INTERSECT':
- operation = 'intersection'
- else:
- operation = mod.operation.lower()
- mod_ob_name = string_strip_hyphen(
- bpy.path.clean_name(mod.object.name)
- )
- mod_matrix = (
- global_matrix @ mod.object.matrix_world
- )
- mod_ob_matrix = MatrixAsPovString(
- mod_matrix
- )
- tabWrite("%s { \n" % operation)
- tabWrite("object { \n")
- tabWrite("%s\n" % data_name)
- tabWrite("%s\n" % matrix_str)
- tabWrite("}\n")
- tabWrite("object { \n")
- tabWrite("%s\n" % ('DATA' + mod_ob_name))
- tabWrite("%s\n" % mod_ob_matrix)
- tabWrite("}\n")
- tabWrite("}\n")
- break
- if no_boolean:
- tabWrite("object { \n")
- tabWrite("%s\n" % data_name)
- tabWrite("%s\n" % matrix_str)
- tabWrite("}\n")
-
- def exportWorld(world):
- """write world as POV backgrounbd and sky_sphere to exported file """
- render = scene.pov
- camera = scene.camera
- matrix = global_matrix @ camera.matrix_world
- if not world:
- return
- #############Maurice####################################
- # These lines added to get sky gradient (visible with PNG output)
- if world:
- # For simple flat background:
- if not world.pov.use_sky_blend:
- # Non fully transparent background could premultiply alpha and avoid anti-aliasing
- # display issue:
- if render.alpha_mode == 'TRANSPARENT':
- tabWrite(
- "background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n"
- % (world.pov.horizon_color[:])
- )
- # Currently using no alpha with Sky option:
- elif render.alpha_mode == 'SKY':
- tabWrite(
- "background {rgbt<%.3g, %.3g, %.3g, 0>}\n"
- % (world.pov.horizon_color[:])
- )
- # StraightAlpha:
- # XXX Does not exists anymore
- # else:
- # tabWrite("background {rgbt<%.3g, %.3g, %.3g, 1>}\n" % (world.pov.horizon_color[:]))
-
- worldTexCount = 0
- # For Background image textures
- for (
- t
- ) in (
- world.pov_texture_slots
- ): # risk to write several sky_spheres but maybe ok.
- if t:
- tex = bpy.data.textures[t.texture]
- if tex.type is not None:
- worldTexCount += 1
- # XXX No enable checkbox for world textures yet (report it?)
- # if t and tex.type == 'IMAGE' and t.use:
- if tex.type == 'IMAGE':
- image_filename = path_image(tex.image)
- if tex.image.filepath != image_filename:
- tex.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.pov.org/pov.newusers/thread/%3Cweb.4a5cddf4e9c9822ba2f93e20@news.pov.org%3E/
- # Replace 4/3 by the ratio of each image found by some custom or existing
- # function
- # 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))
- # using camera rotation valuesdirectly from blender seems much easier
- if t_blend.texture_coords == 'ANGMAP':
- mappingBlend = ""
- else:
- # POV-Ray "scale" is not a number of repetitions factor, but its
- # inverse, a standard scale factor.
- # 0.5 Offset is needed relatively to scale because center of the
- # UV scale is 0.5,0.5 in blender and 0,0 in POV
- # Further Scale by 2 and translate by -1 are
- # required for the sky_sphere not to repeat
-
- mappingBlend = (
- "scale 2 scale <%.4g,%.4g,%.4g> translate -1 "
- "translate <%.4g,%.4g,%.4g> rotate<0,0,0> "
- % (
- (1.0 / t_blend.scale.x),
- (1.0 / t_blend.scale.y),
- (1.0 / t_blend.scale.z),
- 0.5
- - (0.5 / t_blend.scale.x)
- - t_blend.offset.x,
- 0.5
- - (0.5 / t_blend.scale.y)
- - t_blend.offset.y,
- t_blend.offset.z,
- )
- )
-
- # 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.
- tabWrite("sky_sphere {\n")
- tabWrite("pigment {\n")
- tabWrite(
- "image_map{%s \"%s\" %s}\n"
- % (
- imageFormat(texturesBlend),
- texturesBlend,
- imgMapBG(t_blend),
- )
- )
- tabWrite("}\n")
- tabWrite("%s\n" % (mappingBlend))
- # The following layered pigment opacifies to black over the texture for
- # transmit below 1 or otherwise adds to itself
- tabWrite(
- "pigment {rgb 0 transmit %s}\n" % (tex.intensity)
- )
- tabWrite("}\n")
- # tabWrite("scale 2\n")
- # tabWrite("translate -1\n")
-
- # For only Background gradient
-
- if worldTexCount == 0:
- if world.pov.use_sky_blend:
- tabWrite("sky_sphere {\n")
- tabWrite("pigment {\n")
- # maybe Should follow the advice of POV doc about replacing gradient
- # for skysphere..5.5
- tabWrite("gradient y\n")
- tabWrite("color_map {\n")
- # XXX Does not exists anymore
- # if render.alpha_mode == 'STRAIGHT':
- # tabWrite("[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.horizon_color[:]))
- # tabWrite("[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.zenith_color[:]))
- if render.alpha_mode == 'TRANSPARENT':
- tabWrite(
- "[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n"
- % (world.pov.horizon_color[:])
- )
- # aa premult not solved with transmit 1
- tabWrite(
- "[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n"
- % (world.pov.zenith_color[:])
- )
- else:
- tabWrite(
- "[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n"
- % (world.pov.horizon_color[:])
- )
- tabWrite(
- "[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n"
- % (world.pov.zenith_color[:])
- )
- tabWrite("}\n")
- tabWrite("}\n")
- tabWrite("}\n")
- # Sky_sphere alpha (transmit) is not translating into image alpha the same
- # way as 'background'
-
- # if world.pov.light_settings.use_indirect_light:
- # scene.pov.radio_enable=1
-
- # Maybe change the above to a function copyInternalRenderer settings when
- # user pushes a button, then:
- # scene.pov.radio_enable = world.pov.light_settings.use_indirect_light
- # and other such translations but maybe this would not be allowed either?
-
- ###############################################################
-
- mist = world.mist_settings
-
- if mist.use_mist:
- tabWrite("fog {\n")
- if mist.falloff == 'LINEAR':
- tabWrite(
- "distance %.6f\n" % ((mist.start + mist.depth) * 0.368)
- )
- elif mist.falloff == 'QUADRATIC': # n**2 or squrt(n)?
- tabWrite(
- "distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368)
- )
- elif mist.falloff == 'INVERSE_QUADRATIC': # n**2 or squrt(n)?
- tabWrite(
- "distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368)
- )
- tabWrite(
- "color rgbt<%.3g, %.3g, %.3g, %.3g>\n"
- % (*world.pov.horizon_color, 1.0 - mist.intensity)
- )
- # tabWrite("fog_offset %.6f\n" % mist.start) #create a pov property to prepend
- # tabWrite("fog_alt %.6f\n" % mist.height) #XXX right?
- # tabWrite("turbulence 0.2\n")
- # tabWrite("turb_depth 0.3\n")
- tabWrite("fog_type 1\n") # type2 for height
- tabWrite("}\n")
- if scene.pov.media_enable:
- tabWrite("media {\n")
- tabWrite(
- "scattering { %d, rgb %.12f*<%.4g, %.4g, %.4g>\n"
- % (
- int(scene.pov.media_scattering_type),
- (scene.pov.media_diffusion_scale),
- *(scene.pov.media_diffusion_color[:]),
- )
- )
- if scene.pov.media_scattering_type == '5':
- tabWrite("eccentricity %.3g\n" % scene.pov.media_eccentricity)
- tabWrite("}\n")
- tabWrite(
- "absorption %.12f*<%.4g, %.4g, %.4g>\n"
- % (
- scene.pov.media_absorption_scale,
- *(scene.pov.media_absorption_color[:]),
- )
- )
- tabWrite("\n")
- tabWrite("samples %.d\n" % scene.pov.media_samples)
- tabWrite("}\n")
-
- def exportGlobalSettings(scene):
+ def export_global_settings(scene):
"""write all POV global settings to exported file """
- tabWrite("global_settings {\n")
- tabWrite("assumed_gamma 1.0\n")
- tabWrite("max_trace_level %d\n" % scene.pov.max_trace_level)
+ tab_write("global_settings {\n")
+ tab_write("assumed_gamma 1.0\n")
+ tab_write("max_trace_level %d\n" % scene.pov.max_trace_level)
- # Deprecated (autodetected in pov3.8):
- # if scene.pov.charset != 'ascii':
- # file.write(" charset %s\n" % scene.pov.charset)
if scene.pov.global_settings_advanced:
- if scene.pov.radio_enable == False:
+ 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(
- " max_intersections %s\n" % scene.pov.max_intersections
- )
+ 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:
- tabWrite("radiosity {\n")
- tabWrite("adc_bailout %.4g\n" % scene.pov.radio_adc_bailout)
- tabWrite("brightness %.4g\n" % scene.pov.radio_brightness)
- tabWrite("count %d\n" % scene.pov.radio_count)
- tabWrite("error_bound %.4g\n" % scene.pov.radio_error_bound)
- tabWrite("gray_threshold %.4g\n" % scene.pov.radio_gray_threshold)
- tabWrite(
- "low_error_factor %.4g\n" % scene.pov.radio_low_error_factor
- )
- tabWrite("maximum_reuse %.4g\n" % scene.pov.radio_maximum_reuse)
- tabWrite("minimum_reuse %.4g\n" % scene.pov.radio_minimum_reuse)
- tabWrite("nearest_count %d\n" % scene.pov.radio_nearest_count)
- tabWrite("pretrace_start %.3g\n" % scene.pov.radio_pretrace_start)
- tabWrite("pretrace_end %.3g\n" % scene.pov.radio_pretrace_end)
- tabWrite("recursion_limit %d\n" % scene.pov.radio_recursion_limit)
- tabWrite("always_sample %d\n" % scene.pov.radio_always_sample)
- tabWrite("normal %d\n" % scene.pov.radio_normal)
- tabWrite("media %d\n" % scene.pov.radio_media)
- tabWrite("subsurface %d\n" % scene.pov.radio_subsurface)
- tabWrite("}\n")
- onceSss = 1
- onceAmbient = 1
- oncePhotons = 1
+ tab_write("radiosity {\n")
+ tab_write("adc_bailout %.4g\n" % scene.pov.radio_adc_bailout)
+ tab_write("brightness %.4g\n" % scene.pov.radio_brightness)
+ tab_write("count %d\n" % scene.pov.radio_count)
+ tab_write("error_bound %.4g\n" % scene.pov.radio_error_bound)
+ tab_write("gray_threshold %.4g\n" % scene.pov.radio_gray_threshold)
+ tab_write("low_error_factor %.4g\n" % scene.pov.radio_low_error_factor)
+ tab_write("maximum_reuse %.4g\n" % scene.pov.radio_maximum_reuse)
+ tab_write("minimum_reuse %.4g\n" % scene.pov.radio_minimum_reuse)
+ tab_write("nearest_count %d\n" % scene.pov.radio_nearest_count)
+ tab_write("pretrace_start %.3g\n" % scene.pov.radio_pretrace_start)
+ tab_write("pretrace_end %.3g\n" % scene.pov.radio_pretrace_end)
+ tab_write("recursion_limit %d\n" % scene.pov.radio_recursion_limit)
+ tab_write("always_sample %d\n" % scene.pov.radio_always_sample)
+ tab_write("normal %d\n" % scene.pov.radio_normal)
+ tab_write("media %d\n" % scene.pov.radio_media)
+ tab_write("subsurface %d\n" % scene.pov.radio_subsurface)
+ tab_write("}\n")
+ once_sss = 1
+ once_ambient = 1
+ once_photons = 1
for material in bpy.data.materials:
- if material.pov_subsurface_scattering.use and onceSss:
+ if material.pov_subsurface_scattering.use and once_sss:
# In pov, the scale has reversed influence compared to blender. these number
# should correct that
- tabWrite(
- "mm_per_unit %.6f\n"
- % (material.pov_subsurface_scattering.scale * 1000.0)
+ tab_write(
+ "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
+ sslt_samples = (11 - material.pov_subsurface_scattering.error_threshold) * 10
- tabWrite(
- "subsurface { samples %d, %d }\n"
- % (sslt_samples, sslt_samples / 10)
- )
- onceSss = 0
+ tab_write("subsurface { samples %d, %d }\n" % (sslt_samples, sslt_samples / 10))
+ once_sss = 0
- if world and onceAmbient:
- tabWrite(
- "ambient_light rgb<%.3g, %.3g, %.3g>\n"
- % world.pov.ambient_color[:]
- )
- onceAmbient = 0
+ if world and once_ambient:
+ tab_write("ambient_light rgb<%.3g, %.3g, %.3g>\n" % world.pov.ambient_color[:])
+ once_ambient = 0
if scene.pov.photon_enable:
- if oncePhotons and (
- material.pov.refraction_type == "2"
- or material.pov.photons_reflection == True
+ if once_photons and (
+ material.pov.refraction_type == "2" or material.pov.photons_reflection
):
- tabWrite("photons {\n")
- tabWrite("spacing %.6f\n" % scene.pov.photon_spacing)
- tabWrite(
- "max_trace_level %d\n"
- % scene.pov.photon_max_trace_level
- )
- tabWrite(
- "adc_bailout %.3g\n" % scene.pov.photon_adc_bailout
- )
- tabWrite(
+ tab_write("photons {\n")
+ tab_write("spacing %.6f\n" % scene.pov.photon_spacing)
+ tab_write("max_trace_level %d\n" % scene.pov.photon_max_trace_level)
+ tab_write("adc_bailout %.3g\n" % scene.pov.photon_adc_bailout)
+ tab_write(
"gather %d, %d\n"
- % (
- scene.pov.photon_gather_min,
- scene.pov.photon_gather_max,
- )
+ % (scene.pov.photon_gather_min, scene.pov.photon_gather_max)
)
if scene.pov.photon_map_file_save_load in {'save'}:
- filePhName = 'Photon_map_file.ph'
+ ph_file_name = 'Photon_map_file.ph'
if scene.pov.photon_map_file != '':
- filePhName = scene.pov.photon_map_file + '.ph'
- filePhDir = tempfile.gettempdir()
+ 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):
- filePhDir = path
- fullFileName = os.path.join(filePhDir, filePhName)
- tabWrite('save_file "%s"\n' % fullFileName)
- scene.pov.photon_map_file = fullFileName
+ ph_file_dir = path
+ full_file_name = os.path.join(ph_file_dir, ph_file_name)
+ tab_write('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'}:
- fullFileName = bpy.path.abspath(
- scene.pov.photon_map_file
- )
- if os.path.exists(fullFileName):
- tabWrite('load_file "%s"\n' % fullFileName)
- tabWrite("}\n")
- oncePhotons = 0
+ full_file_name = bpy.path.abspath(scene.pov.photon_map_file)
+ if os.path.exists(full_file_name):
+ tab_write('load_file "%s"\n' % full_file_name)
+ tab_write("}\n")
+ once_photons = 0
- tabWrite("}\n")
-
- def exportCustomCode():
- """write all POV user defined custom code to exported file """
- # Write CurrentAnimation Frame for use in Custom POV Code
- file.write(
- "#declare CURFRAMENUM = %d;\n" % bpy.context.scene.frame_current
- )
- # Change path and uncomment to add an animated include file by hand:
- file.write(
- "//#include \"/home/user/directory/animation_include_file.inc\"\n"
- )
- for txt in bpy.data.texts:
- if txt.pov.custom_code == 'both':
- # Why are the newlines needed?
- file.write("\n")
- file.write(txt.as_string())
- file.write("\n")
+ tab_write("}\n")
# sel = renderable_objects(scene) #removed for booleans
if comments:
@@ -4990,51 +687,44 @@ def write_pov(filename, scene=None, info_callback=None):
"//--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("#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"
+ "#declare Default_texture = texture{pigment {rgb 0.8} " "finish {brilliance 3.8} }\n\n"
)
if comments:
file.write("\n//--Global settings--\n\n")
- exportGlobalSettings(scene)
+ export_global_settings(scene)
if comments:
file.write("\n//--Custom Code--\n\n")
- exportCustomCode()
+ scripting.export_custom_code(file)
if comments:
file.write("\n//--Patterns Definitions--\n\n")
- LocalPatternNames = []
+ local_pattern_names = []
for texture in bpy.data.textures: # ok?
if texture.users > 0:
- currentPatName = string_strip_hyphen(
- bpy.path.clean_name(texture.name)
- )
+ current_pat_name = string_strip_hyphen(bpy.path.clean_name(texture.name))
# string_strip_hyphen(patternNames[texture.name]) #maybe instead of the above
- LocalPatternNames.append(currentPatName)
+ 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" % currentPatName)
- file.write(shading.exportPattern(texture, string_strip_hyphen))
+ 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(shading.export_pattern(texture))
file.write("\n")
if comments:
file.write("\n//--Background--\n\n")
- exportWorld(scene.world)
+ scenography.export_world(scene.world, scene, global_matrix, tab_write)
if comments:
file.write("\n//--Cameras--\n\n")
- exportCamera()
+ scenography.export_camera(scene, global_matrix, render, tab_write)
if comments:
file.write("\n//--Lamps--\n\n")
@@ -5047,20 +737,57 @@ def write_pov(filename, scene=None, info_callback=None):
csg_list.append(mod.object)
if csg_list != []:
csg = False
- sel = no_renderable_objects(scene)
- exportMeshes(scene, sel, csg)
+ sel = no_renderable_objects()
+ object_mesh_topology.export_meshes(
+ preview_dir,
+ file,
+ scene,
+ sel,
+ csg,
+ string_strip_hyphen,
+ safety,
+ write_object_modifiers,
+ material_names_dictionary,
+ write_object_material,
+ scenography.exported_lights_count,
+ unpacked_images,
+ image_format,
+ img_map,
+ img_map_transforms,
+ path_image,
+ smoke_path,
+ global_matrix,
+ write_matrix,
+ using_uberpov,
+ comments,
+ linebreaksinlists,
+ tab,
+ tab_level,
+ tab_write,
+ info_callback,
+ )
csg = True
sel = renderable_objects(scene)
- exportLamps(
- [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as != 'RAINBOW')]
+ scenography.export_lights(
+ [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as != 'RAINBOW')],
+ file,
+ scene,
+ global_matrix,
+ write_matrix,
+ tab_write,
)
if comments:
file.write("\n//--Rainbows--\n\n")
- exportRainbows(
- [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as == 'RAINBOW')]
+ scenography.export_rainbows(
+ [L for L in sel if (L.type == 'LIGHT' and L.pov.object_as == 'RAINBOW')],
+ file,
+ scene,
+ global_matrix,
+ write_matrix,
+ tab_write,
)
if comments:
@@ -5068,10 +795,9 @@ def write_pov(filename, scene=None, info_callback=None):
for c in sel:
if c.is_modified(scene, 'RENDER'):
continue # don't export as pov curves objects with modifiers, but as mesh
- elif c.type == 'CURVE' and (
- c.pov.curveshape in {'lathe', 'sphere_sweep', 'loft', 'birail'}
- ):
- exportCurves(scene, c)
+ # Implicit else-if (as not skipped by previous "continue")
+ if c.type == 'CURVE' and (c.pov.curveshape in {'lathe', 'sphere_sweep', 'loft', 'birail'}):
+ object_curve_topology.export_curves(c, string_strip_hyphen, global_matrix, tab_write)
if comments:
file.write("\n//--Material Definitions--\n\n")
@@ -5079,84 +805,101 @@ def write_pov(filename, scene=None, info_callback=None):
file.write("#default{ pigment{ color srgb 0.8 }}\n")
# Convert all materials to strings we can access directly per vertex.
# exportMaterials()
- shading.writeMaterial(
+ shading.write_material(
using_uberpov,
DEF_MAT_NAME,
- scene,
- tabWrite,
+ tab_write,
safety,
comments,
- uniqueName,
- materialNames,
+ 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
- povMatName = string_strip_hyphen(
- bpy.path.clean_name(material.name)
- )
+ pov_mat_name = string_strip_hyphen(bpy.path.clean_name(material.name))
if len(ntree.nodes) == 0:
- file.write(
- '#declare %s = texture {%s}\n' % (povMatName, color)
- )
+ file.write('#declare %s = texture {%s}\n' % (pov_mat_name, pigment_color))
else:
- shading.write_nodes(scene, povMatName, ntree, file)
+ shading.write_nodes(scene, 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"
- ):
- povMatName = (
+ if link.to_node.bl_idname == "PovrayOutputNode":
+ pov_mat_name = (
string_strip_hyphen(
- bpy.path.clean_name(
- link.from_node.name
- )
+ bpy.path.clean_name(link.from_node.name)
)
- + "_%s" % povMatName
+ + "_%s" % pov_mat_name
)
else:
file.write(
- '#declare %s = texture {%s}\n'
- % (povMatName, color)
+ '#declare %s = texture {%s}\n' % (pov_mat_name, pigment_color)
)
else:
- shading.writeMaterial(
+ shading.write_material(
using_uberpov,
DEF_MAT_NAME,
- scene,
- tabWrite,
+ tab_write,
safety,
comments,
- uniqueName,
- materialNames,
+ unique_name,
+ material_names_dictionary,
material,
)
# attributes are all the variables needed by the other python file...
if comments:
file.write("\n")
- exportMeta([m for m in sel if m.type == 'META'])
+ export_meta([m for m in sel if m.type == 'META'])
if comments:
file.write("//--Mesh objects--\n")
-
- #tbefore = time.time()
- exportMeshes(scene, sel, csg)
- #totime = time.time() - tbefore
- #print("exportMeshes took" + str(totime))
+ # tbefore = time.time()
+ object_mesh_topology.export_meshes(
+ preview_dir,
+ file,
+ scene,
+ sel,
+ csg,
+ string_strip_hyphen,
+ safety,
+ write_object_modifiers,
+ material_names_dictionary,
+ write_object_material,
+ scenography.exported_lights_count,
+ unpacked_images,
+ image_format,
+ img_map,
+ img_map_transforms,
+ path_image,
+ smoke_path,
+ global_matrix,
+ write_matrix,
+ using_uberpov,
+ comments,
+ linebreaksinlists,
+ tab,
+ tab_level,
+ tab_write,
+ info_callback,
+ )
+ # totime = time.time() - tbefore
+ # print("export_meshes took" + str(totime))
# What follow used to happen here:
- # exportCamera()
- # exportWorld(scene.world)
- # exportGlobalSettings(scene)
+ # export_camera()
+ # scenography.export_world(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.
@@ -5166,13 +909,9 @@ def write_pov(filename, scene=None, info_callback=None):
# print("pov file closed %s" % file.closed)
-def write_pov_ini(
- scene, filename_ini, filename_log, filename_pov, filename_image
-):
+def write_pov_ini(scene, filename_ini, filename_log, filename_pov, filename_image):
"""Write ini file."""
- feature_set = bpy.context.preferences.addons[
- __package__
- ].preferences.branch_feature_set_povray
+ feature_set = bpy.context.preferences.addons[__package__].preferences.branch_feature_set_povray
using_uberpov = feature_set == 'uberpov'
# scene = bpy.data.scenes[0]
scene = bpy.context.scene
@@ -5182,7 +921,7 @@ def write_pov_ini(
y = int(render.resolution_y * render.resolution_percentage * 0.01)
file = open(filename_ini, "w")
- file.write("Version=3.8\n")
+ 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:
@@ -5202,9 +941,7 @@ def write_pov_ini(
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
+ 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)
@@ -5228,16 +965,10 @@ def write_pov_ini(
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
- )
+ 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("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")
@@ -5270,15 +1001,12 @@ class PovrayRender(bpy.types.RenderEngine):
if pov_binary:
if os.path.exists(pov_binary):
return pov_binary
- else:
- print(
- "User Preferences path to povray %r NOT FOUND, checking $PATH"
- % pov_binary
- )
+ # Implicit else, as here return was still not triggered:
+ print("User Preferences path to povray %r NOT FOUND, checking $PATH" % pov_binary)
# Windows Only
# assume if there is a 64bit binary that the user has a 64bit capable OS
- if sys.platform[:3] == "win":
+ if platform.startswith('win'):
import winreg
win_reg_key = winreg.OpenKey(
@@ -5317,36 +1045,27 @@ class PovrayRender(bpy.types.RenderEngine):
return pov_binary
return ""
- def _export(self, depsgraph, povPath, renderImagePath):
+ def _export(self, depsgraph, pov_path, image_render_path):
"""gather all necessary output files paths user defined and auto generated and export there"""
- import tempfile
scene = bpy.context.scene
if scene.pov.tempfiles_enable:
- self._temp_file_in = tempfile.NamedTemporaryFile(
- suffix=".pov", delete=False
- ).name
+ self._temp_file_in = tempfile.NamedTemporaryFile(suffix=".pov", delete=False).name
# PNG with POV 3.7, can show the background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
- self._temp_file_out = tempfile.NamedTemporaryFile(
- suffix=".png", delete=False
- ).name
+ self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".png", delete=False).name
# self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
- self._temp_file_ini = tempfile.NamedTemporaryFile(
- suffix=".ini", delete=False
- ).name
- self._temp_file_log = os.path.join(
- tempfile.gettempdir(), "alltext.out"
- )
+ self._temp_file_ini = tempfile.NamedTemporaryFile(suffix=".ini", delete=False).name
+ self._temp_file_log = os.path.join(tempfile.gettempdir(), "alltext.out")
else:
- self._temp_file_in = povPath + ".pov"
+ self._temp_file_in = pov_path + ".pov"
# PNG with POV 3.7, can show the background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
- self._temp_file_out = renderImagePath + ".png"
- # self._temp_file_out = renderImagePath + ".tga"
- self._temp_file_ini = povPath + ".ini"
- logPath = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
- self._temp_file_log = os.path.join(logPath, "alltext.out")
+ self._temp_file_out = image_render_path + ".png"
+ # self._temp_file_out = image_render_path + ".tga"
+ self._temp_file_ini = pov_path + ".ini"
+ log_path = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
+ self._temp_file_log = os.path.join(log_path, "alltext.out")
'''
self._temp_file_in = "/test.pov"
# PNG with POV 3.7, can show the background color with alpha. In the long run using the
@@ -5377,17 +1096,11 @@ class PovrayRender(bpy.types.RenderEngine):
pov_binary = PovrayRender._locate_binary()
if not pov_binary:
- print(
- "POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed"
- )
+ print("POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed")
return False
write_pov_ini(
- scene,
- self._temp_file_ini,
- self._temp_file_log,
- self._temp_file_in,
- self._temp_file_out,
+ scene, self._temp_file_ini, self._temp_file_log, self._temp_file_in, self._temp_file_out
)
print("***-STARTING-***")
@@ -5395,11 +1108,11 @@ class PovrayRender(bpy.types.RenderEngine):
extra_args = []
if scene.pov.command_line_switches != "":
- for newArg in scene.pov.command_line_switches.split(" "):
- extra_args.append(newArg)
+ for new_arg in scene.pov.command_line_switches.split(" "):
+ extra_args.append(new_arg)
self._is_windows = False
- if sys.platform[:3] == "win":
+ if platform.startswith('win'):
self._is_windows = True
if "/EXIT" not in extra_args and not scene.pov.pov_editor:
extra_args.append("/EXIT")
@@ -5442,7 +1155,7 @@ class PovrayRender(bpy.types.RenderEngine):
# and Windows does not know how to delete a file in use!
time.sleep(self.DELAY)
for i in unpacked_images:
- for c in range(5):
+ for j in range(5):
try:
os.unlink(i)
break
@@ -5453,7 +1166,6 @@ class PovrayRender(bpy.types.RenderEngine):
def render(self, depsgraph):
"""Export necessary files from text editor and render image."""
- import tempfile
scene = bpy.context.scene
r = scene.render
@@ -5475,8 +1187,11 @@ class PovrayRender(bpy.types.RenderEngine):
except OSError:
pass
return False
-
- poll_result = self._process.poll()
+ try:
+ poll_result = self._process.poll()
+ except AttributeError:
+ print("***CHECK POV PATH IN PREFERENCES***")
+ return False
# POV process is finisehd, one way or the other
if poll_result is not None:
if poll_result < 0:
@@ -5488,27 +1203,18 @@ class PovrayRender(bpy.types.RenderEngine):
if bpy.context.scene.pov.text_block != "":
if scene.pov.tempfiles_enable:
- self._temp_file_in = tempfile.NamedTemporaryFile(
- suffix=".pov", delete=False
- ).name
- self._temp_file_out = tempfile.NamedTemporaryFile(
- suffix=".png", delete=False
- ).name
+ self._temp_file_in = tempfile.NamedTemporaryFile(suffix=".pov", delete=False).name
+ self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".png", delete=False).name
# self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
- self._temp_file_ini = tempfile.NamedTemporaryFile(
- suffix=".ini", delete=False
- ).name
- self._temp_file_log = os.path.join(
- tempfile.gettempdir(), "alltext.out"
- )
+ self._temp_file_ini = tempfile.NamedTemporaryFile(suffix=".ini", delete=False).name
+ self._temp_file_log = os.path.join(tempfile.gettempdir(), "alltext.out")
else:
- povPath = scene.pov.text_block
- renderImagePath = os.path.splitext(povPath)[0]
- self._temp_file_out = os.path.join(preview_dir, renderImagePath)
- self._temp_file_in = os.path.join(preview_dir, povPath)
+ pov_path = scene.pov.text_block
+ image_render_path = os.path.splitext(pov_path)[0]
+ self._temp_file_out = os.path.join(preview_dir, image_render_path)
+ self._temp_file_in = os.path.join(preview_dir, pov_path)
self._temp_file_ini = os.path.join(
- preview_dir,
- (os.path.splitext(self._temp_file_in)[0] + ".INI"),
+ preview_dir, (os.path.splitext(self._temp_file_in)[0] + ".INI")
)
self._temp_file_log = os.path.join(preview_dir, "alltext.out")
@@ -5533,15 +1239,11 @@ class PovrayRender(bpy.types.RenderEngine):
pov_binary = PovrayRender._locate_binary()
if not pov_binary:
- print(
- "POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed"
- )
+ print("POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed")
return False
# start ini UI options export
- self.update_stats(
- "", "POV-Ray 3.7: Exporting ini options from Blender"
- )
+ self.update_stats("", "POV-Ray 3.7: Exporting ini options from Blender")
write_pov_ini(
scene,
@@ -5556,10 +1258,10 @@ class PovrayRender(bpy.types.RenderEngine):
extra_args = []
if scene.pov.command_line_switches != "":
- for newArg in scene.pov.command_line_switches.split(" "):
- extra_args.append(newArg)
+ for new_arg in scene.pov.command_line_switches.split(" "):
+ extra_args.append(new_arg)
- if sys.platform[:3] == "win":
+ if platform.startswith('win'):
if "/EXIT" not in extra_args and not scene.pov.pov_editor:
extra_args.append("/EXIT")
else:
@@ -5568,8 +1270,8 @@ class PovrayRender(bpy.types.RenderEngine):
# Start Rendering!
try:
- if (
- sys.platform[:3] != "win" and scene.pov.sdl_window_enable
+ if scene.pov.sdl_window_enable and not platform.startswith(
+ 'win'
): # segfault on linux == False !!!
env = {'POV_DISPLAY_SCALED': 'off'}
env.update(os.environ)
@@ -5638,12 +1340,10 @@ class PovrayRender(bpy.types.RenderEngine):
## r.image_settings.file_format = 'TARGA'
## r.image_settings.color_mode = 'RGBA'
- blendSceneName = bpy.data.filepath.split(os.path.sep)[-1].split(
- "."
- )[0]
- povSceneName = ""
- povPath = ""
- renderImagePath = ""
+ blend_scene_name = bpy.data.filepath.split(os.path.sep)[-1].split(".")[0]
+ pov_scene_name = ""
+ pov_path = ""
+ image_render_path = ""
# has to be called to update the frame on exporting animations
scene.frame_set(scene.frame_current)
@@ -5651,54 +1351,49 @@ class PovrayRender(bpy.types.RenderEngine):
if not scene.pov.tempfiles_enable:
# check paths
- povPath = bpy.path.abspath(scene.pov.scene_path).replace(
- '\\', '/'
- )
- if povPath == "":
+ pov_path = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
+ if pov_path == "":
if bpy.data.is_saved:
- povPath = bpy.path.abspath("//")
+ pov_path = bpy.path.abspath("//")
else:
- povPath = tempfile.gettempdir()
- elif povPath.endswith("/"):
- if povPath == "/":
- povPath = bpy.path.abspath("//")
+ pov_path = tempfile.gettempdir()
+ elif pov_path.endswith("/"):
+ if pov_path == "/":
+ pov_path = bpy.path.abspath("//")
else:
- povPath = bpy.path.abspath(scene.pov.scene_path)
+ pov_path = bpy.path.abspath(scene.pov.scene_path)
- if not os.path.exists(povPath):
+ if not os.path.exists(pov_path):
try:
- os.makedirs(povPath)
- except:
+ os.makedirs(pov_path)
+ except BaseException as e:
+ print(e.__doc__)
+ print('An exception occurred: {}'.format(e))
import traceback
traceback.print_exc()
- print(
- "POV-Ray 3.7: Cannot create scenes directory: %r"
- % povPath
- )
+ print("POV-Ray 3.7: Cannot create scenes directory: %r" % pov_path)
self.update_stats(
- "",
- "POV-Ray 3.7: Cannot create scenes directory %r"
- % povPath,
+ "", "POV-Ray 3.7: Cannot create scenes directory %r" % pov_path
)
time.sleep(2.0)
# return
'''
# Bug in POV-Ray RC3
- renderImagePath = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
- if renderImagePath == "":
+ image_render_path = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
+ if image_render_path == "":
if bpy.data.is_saved:
- renderImagePath = bpy.path.abspath("//")
+ image_render_path = bpy.path.abspath("//")
else:
- renderImagePath = tempfile.gettempdir()
- #print("Path: " + renderImagePath)
+ image_render_path = tempfile.gettempdir()
+ #print("Path: " + image_render_path)
elif path.endswith("/"):
- if renderImagePath == "/":
- renderImagePath = bpy.path.abspath("//")
+ if image_render_path == "/":
+ image_render_path = bpy.path.abspath("//")
else:
- renderImagePath = bpy.path.abspath(scene.pov.renderimage_path)
+ image_render_path = bpy.path.abspath(scene.pov.)
if not os.path.exists(path):
print("POV-Ray 3.7: Cannot find render image directory")
self.update_stats("", "POV-Ray 3.7: Cannot find render image directory")
@@ -5708,38 +1403,38 @@ class PovrayRender(bpy.types.RenderEngine):
# check name
if scene.pov.scene_name == "":
- if blendSceneName != "":
- povSceneName = blendSceneName
+ if blend_scene_name != "":
+ pov_scene_name = blend_scene_name
else:
- povSceneName = "untitled"
+ pov_scene_name = "untitled"
else:
- povSceneName = scene.pov.scene_name
- if os.path.isfile(povSceneName):
- povSceneName = os.path.basename(povSceneName)
- povSceneName = povSceneName.split('/')[-1].split('\\')[-1]
- if not povSceneName:
+ pov_scene_name = scene.pov.scene_name
+ if os.path.isfile(pov_scene_name):
+ pov_scene_name = os.path.basename(pov_scene_name)
+ pov_scene_name = pov_scene_name.split('/')[-1].split('\\')[-1]
+ if not pov_scene_name:
print("POV-Ray 3.7: Invalid scene name")
self.update_stats("", "POV-Ray 3.7: Invalid scene name")
time.sleep(2.0)
# return
- povSceneName = os.path.splitext(povSceneName)[0]
+ pov_scene_name = os.path.splitext(pov_scene_name)[0]
- print("Scene name: " + povSceneName)
- print("Export path: " + povPath)
- povPath = os.path.join(povPath, povSceneName)
- povPath = os.path.realpath(povPath)
+ print("Scene name: " + pov_scene_name)
+ print("Export path: " + pov_path)
+ pov_path = os.path.join(pov_path, pov_scene_name)
+ pov_path = os.path.realpath(pov_path)
# for now this has to be the same like the pov output. Bug in POV-Ray RC3.
- # renderImagePath = renderImagePath + "\\" + povSceneName
- renderImagePath = povPath # Bugfix for POV-Ray RC3 bug
- # renderImagePath = os.path.realpath(renderImagePath) # Bugfix for POV-Ray RC3 bug
+ # image_render_path = image_render_path + "\\" + pov_scene_name
+ image_render_path = pov_path # Bugfix for POV-Ray RC3 bug
+ # image_render_path = os.path.realpath(image_render_path) # Bugfix for POV-Ray RC3 bug
- # print("Export path: %s" % povPath)
- # print("Render Image path: %s" % renderImagePath)
+ # print("Export path: %s" % pov_path)
+ # print("Render Image path: %s" % image_render_path)
# start export
self.update_stats("", "POV-Ray 3.7: Exporting data from Blender")
- self._export(depsgraph, povPath, renderImagePath)
+ self._export(depsgraph, pov_path, image_render_path)
self.update_stats("", "POV-Ray 3.7: Parsing File")
if not self._render(depsgraph):
@@ -5774,11 +1469,7 @@ class PovrayRender(bpy.types.RenderEngine):
# XXX This is working for UNIX, not sure whether it might need adjustments for
# other OSs
# First replace is for windows
- t_data = (
- str(t_data)
- .replace('\\r\\n', '\\n')
- .replace('\\r', '\r')
- )
+ t_data = str(t_data).replace('\\r\\n', '\\n').replace('\\r', '\r')
lines = t_data.split('\\n')
last_line += lines[0]
lines[0] = last_line
@@ -5789,11 +1480,7 @@ class PovrayRender(bpy.types.RenderEngine):
_pov_rendering = True
match = percent.findall(str(data))
if match:
- self.update_stats(
- "",
- "POV-Ray 3.7: Rendering File (%s%%)"
- % match[-1],
- )
+ self.update_stats("", "POV-Ray 3.7: Rendering File (%s%%)" % match[-1])
else:
self.update_stats("", "POV-Ray 3.7: Rendering File")
@@ -5882,107 +1569,116 @@ class PovrayRender(bpy.types.RenderEngine):
# print(filename_log) #bring the pov log to blender console with proper path?
with open(
- self._temp_file_log,
- encoding='utf-8'
+ self._temp_file_log, encoding='utf-8'
) as f: # The with keyword automatically closes the file when you are done
msg = f.read()
- #if isinstance(msg, str):
- #stdmsg = msg
- #decoded = False
- #else:
- #if type(msg) == bytes:
- #stdmsg = msg.split('\n')
- #stdmsg = msg.encode('utf-8', "replace")
- #stdmsg = msg.encode("utf-8", "replace")
-
- #stdmsg = msg.decode(encoding)
- #decoded = True
- #msg.encode('utf-8').decode('utf-8')
+ # if isinstance(msg, str):
+ # stdmsg = msg
+ # decoded = False
+ # else:
+ # if type(msg) == bytes:
+ # stdmsg = msg.split('\n')
+ # stdmsg = msg.encode('utf-8', "replace")
+ # stdmsg = msg.encode("utf-8", "replace")
+
+ # stdmsg = msg.decode(encoding)
+ # decoded = True
+ # msg.encode('utf-8').decode('utf-8')
+ msg.replace("\t", " ")
print(msg)
# Also print to the interactive console used in POV centric workspace
# To do: get a grip on new line encoding
# and make this a function to be used elsewhere
for win in bpy.context.window_manager.windows:
- if win.screen != None:
+ if win.screen is not None:
scr = win.screen
for area in scr.areas:
if area.type == 'CONSOLE':
- #context override
- #ctx = {'window': win, 'screen': scr, 'area':area}#bpy.context.copy()
+ # context override
+ # ctx = {'window': win, 'screen': scr, 'area':area}#bpy.context.copy()
ctx = {}
ctx['area'] = area
ctx['region'] = area.regions[-1]
ctx['space_data'] = area.spaces.active
- ctx['screen'] = scr#C.screen
+ ctx['screen'] = scr # C.screen
ctx['window'] = win
- #bpy.ops.console.banner(ctx, text = "Hello world")
+ # bpy.ops.console.banner(ctx, text = "Hello world")
bpy.ops.console.clear_line(ctx)
- stdmsg = msg.split('\n') #XXX todo , test and see
+ stdmsg = msg.split('\n') # XXX todo , test and see
for i in stdmsg:
- bpy.ops.console.insert(ctx, text = i)
+ # Crashes if no Terminal displayed on Windows
+ bpy.ops.console.scrollback_append(ctx, text=i, type='INFO')
+ # bpy.ops.console.insert(ctx, text=(i + "\n"))
self.update_stats("", "")
if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
self._cleanup()
- sound_on = bpy.context.preferences.addons[
- __package__
- ].preferences.use_sounds
+ sound_on = bpy.context.preferences.addons[__package__].preferences.use_sounds
+ finished_render_message = "\'Render completed\'"
- if sys.platform[:3] == "win" and sound_on:
+ if platform.startswith('win') and sound_on:
# Could not find tts Windows command so playing beeps instead :-)
# "Korobeiniki"(Коробе́йники)
# aka "A-Type" Tetris theme
import winsound
- winsound.Beep(494,250) #B
- winsound.Beep(370,125) #F
- winsound.Beep(392,125) #G
- winsound.Beep(440,250) #A
- winsound.Beep(392,125) #G
- winsound.Beep(370,125) #F#
- winsound.Beep(330,275) #E
- winsound.Beep(330,125) #E
- winsound.Beep(392,125) #G
- winsound.Beep(494,275) #B
- winsound.Beep(440,125) #A
- winsound.Beep(392,125) #G
- winsound.Beep(370,275) #F
- winsound.Beep(370,125) #F
- winsound.Beep(392,125) #G
- winsound.Beep(440,250) #A
- winsound.Beep(494,250) #B
- winsound.Beep(392,250) #G
- winsound.Beep(330,350) #E
+
+ winsound.Beep(494, 250) # B
+ winsound.Beep(370, 125) # F
+ winsound.Beep(392, 125) # G
+ winsound.Beep(440, 250) # A
+ winsound.Beep(392, 125) # G
+ winsound.Beep(370, 125) # F#
+ winsound.Beep(330, 275) # E
+ winsound.Beep(330, 125) # E
+ winsound.Beep(392, 125) # G
+ winsound.Beep(494, 275) # B
+ winsound.Beep(440, 125) # A
+ winsound.Beep(392, 125) # G
+ winsound.Beep(370, 275) # F
+ winsound.Beep(370, 125) # F
+ winsound.Beep(392, 125) # G
+ winsound.Beep(440, 250) # A
+ winsound.Beep(494, 250) # B
+ winsound.Beep(392, 250) # G
+ winsound.Beep(330, 350) # E
time.sleep(0.5)
- winsound.Beep(440,250) #A
- winsound.Beep(440,150) #A
- winsound.Beep(523,125) #D8
- winsound.Beep(659,250) #E8
- winsound.Beep(587,125) #D8
- winsound.Beep(523,125) #C8
- winsound.Beep(494,250) #B
- winsound.Beep(494,125) #B
- winsound.Beep(392,125) #G
- winsound.Beep(494,250) #B
- winsound.Beep(440,150) #A
- winsound.Beep(392,125) #G
- winsound.Beep(370,250) #F#
- winsound.Beep(370,125) #F#
- winsound.Beep(392,125) #G
- winsound.Beep(440,250) #A
- winsound.Beep(494,250) #B
- winsound.Beep(392,250) #G
- winsound.Beep(330,300) #E
-
- #Does Linux support say command?
- elif sys.platform[:3] != "win" :
- finished_render_message = "\'Render completed\'"
+ winsound.Beep(440, 250) # A
+ winsound.Beep(440, 150) # A
+ winsound.Beep(523, 125) # D8
+ winsound.Beep(659, 250) # E8
+ winsound.Beep(587, 125) # D8
+ winsound.Beep(523, 125) # C8
+ winsound.Beep(494, 250) # B
+ winsound.Beep(494, 125) # B
+ winsound.Beep(392, 125) # G
+ winsound.Beep(494, 250) # B
+ winsound.Beep(440, 150) # A
+ winsound.Beep(392, 125) # G
+ winsound.Beep(370, 250) # F#
+ winsound.Beep(370, 125) # F#
+ winsound.Beep(392, 125) # G
+ winsound.Beep(440, 250) # A
+ winsound.Beep(494, 250) # B
+ winsound.Beep(392, 250) # G
+ winsound.Beep(330, 300) # E
+
+ # Mac supports natively say command
+ elif platform == "darwin":
# We don't want the say command to block Python,
# so we add an ampersand after the message
os.system("say %s &" % (finished_render_message))
+ # While Linux frequently has espeak installed or at least can suggest
+ # Maybe windows could as well ?
+ elif platform == "linux":
+ # We don't want the say command to block Python,
+ # so we add an ampersand after the message
+ os.system("echo %s | espeak &" % (finished_render_message))
+
+
##################################################################################
#################################Operators########################################
##################################################################################
@@ -5993,82 +1689,78 @@ class RenderPovTexturePreview(Operator):
bl_label = "Update preview"
def execute(self, context):
- tex = (
- bpy.context.object.active_material.active_texture
- ) # context.texture
- texPrevName = (
- string_strip_hyphen(bpy.path.clean_name(tex.name)) + "_prev"
- )
+ 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)
- iniPrevFile = os.path.join(preview_dir, "Preview.ini")
- inputPrevFile = os.path.join(preview_dir, "Preview.pov")
- outputPrevFile = os.path.join(preview_dir, texPrevName)
+ 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 ##########################################
- fileIni = open("%s" % iniPrevFile, "w")
- fileIni.write('Version=3.8\n')
- fileIni.write('Input_File_Name="%s"\n' % inputPrevFile)
- fileIni.write('Output_File_Name="%s.png"\n' % outputPrevFile)
- fileIni.write('Library_Path="%s"\n' % preview_dir)
- fileIni.write('Width=256\n')
- fileIni.write('Height=256\n')
- fileIni.write('Pause_When_Done=0\n')
- fileIni.write('Output_File_Type=N\n')
- fileIni.write('Output_Alpha=1\n')
- fileIni.write('Antialias=on\n')
- fileIni.write('Sampling_Method=2\n')
- fileIni.write('Antialias_Depth=3\n')
- fileIni.write('-d\n')
- fileIni.close()
+ file_ini = open("%s" % ini_prev_file, "w")
+ 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')
+ file_ini.close()
##################### pov ##########################################
- filePov = open("%s" % inputPrevFile, "w")
- PATname = "PAT_" + string_strip_hyphen(bpy.path.clean_name(tex.name))
- filePov.write("#declare %s = \n" % PATname)
- filePov.write(shading.exportPattern(tex, string_strip_hyphen))
-
- filePov.write("#declare Plane =\n")
- filePov.write("mesh {\n")
- filePov.write(
+ file_pov = open("%s" % input_prev_file, "w")
+ pat_name = "PAT_" + string_strip_hyphen(bpy.path.clean_name(tex.name))
+ file_pov.write("#declare %s = \n" % pat_name)
+ file_pov.write(shading.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"
)
- filePov.write(
+ file_pov.write(
" triangle {<-2.021,-1.744,-2.021>,<2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n"
)
- filePov.write(" texture{%s}\n" % PATname)
- filePov.write("}\n")
- filePov.write("object {Plane}\n")
- filePov.write("light_source {\n")
- filePov.write(" <0,4.38,-1.92e-07>\n")
- filePov.write(" color rgb<4, 4, 4>\n")
- filePov.write(" parallel\n")
- filePov.write(" point_at <0, 0, -1>\n")
- filePov.write("}\n")
- filePov.write("camera {\n")
- filePov.write(" location <0, 0, 0>\n")
- filePov.write(" look_at <0, 0, -1>\n")
- filePov.write(" right <-1.0, 0, 0>\n")
- filePov.write(" up <0, 1, 0>\n")
- filePov.write(" angle 96.805211\n")
- filePov.write(" rotate <-90.000003, -0.000000, 0.000000>\n")
- filePov.write(" translate <0.000000, 0.000000, 0.000000>\n")
- filePov.write("}\n")
- filePov.close()
+ 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")
+ file_pov.close()
##################### end write ##########################################
pov_binary = PovrayRender._locate_binary()
- if sys.platform[:3] == "win":
+ if platform.startswith('win'):
p1 = subprocess.Popen(
- ["%s" % pov_binary, "/EXIT", "%s" % iniPrevFile],
+ ["%s" % pov_binary, "/EXIT", "%s" % ini_prev_file],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
else:
p1 = subprocess.Popen(
- ["%s" % pov_binary, "-d", "%s" % iniPrevFile],
+ ["%s" % pov_binary, "-d", "%s" % ini_prev_file],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
@@ -6080,9 +1772,9 @@ class RenderPovTexturePreview(Operator):
for n in tree.nodes:
tree.nodes.remove(n)
im = tree.nodes.new("TextureNodeImage")
- pathPrev = "%s.png" % outputPrevFile
- im.image = bpy.data.images.load(pathPrev)
- name = pathPrev
+ 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
@@ -6119,14 +1811,10 @@ classes = (PovrayRender, RenderPovTexturePreview, RunPovTextRender)
def register():
- # from bpy.utils import register_class
-
for cls in classes:
register_class(cls)
def unregister():
- from bpy.utils import unregister_class
-
for cls in reversed(classes):
unregister_class(cls)
diff --git a/render_povray/render_gui.py b/render_povray/render_gui.py
new file mode 100755
index 00000000..018821cb
--- /dev/null
+++ b/render_povray/render_gui.py
@@ -0,0 +1,546 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""User interface for rendering parameters"""
+
+import bpy
+from sys import platform # really import here, as in render.py?
+
+# Or todo: handle this more crossplatform using QTpovray for Linux for instance
+# from os.path import isfile
+from bl_operators.presets import AddPresetBase
+from bpy.utils import register_class, unregister_class
+from bpy.props import EnumProperty
+from bpy.types import Operator, Menu, Panel
+
+
+# Example of wrapping every class 'as is'
+from bl_ui import properties_output
+
+for member in dir(properties_output):
+ subclass = getattr(properties_output, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_output
+
+from bl_ui import properties_freestyle
+
+for member in dir(properties_freestyle):
+ subclass = getattr(properties_freestyle, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ if not (subclass.bl_space_type == 'PROPERTIES' and subclass.bl_context == "render"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+ # subclass.bl_parent_id = "RENDER_PT_POV_filter"
+del properties_freestyle
+
+from bl_ui import properties_view_layer
+
+for member in dir(properties_view_layer):
+ subclass = getattr(properties_view_layer, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_view_layer
+
+# Use some of the existing buttons.
+from bl_ui import properties_render
+
+# DEPRECATED#properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
+# DEPRECATED#properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER')
+# properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
+# TORECREATE##DEPRECATED#properties_render.RENDER_PT_shading.COMPAT_ENGINES.add('POVRAY_RENDER')
+# DEPRECATED#properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_render
+
+
+def check_render_freestyle_svg():
+ """Test if Freestyle SVG Exporter addon is activated
+
+ This addon is currently used to generate the SVG lines file
+ when Freestyle is enabled alongside POV
+ """
+ if "render_freestyle_svg" in bpy.context.preferences.addons.keys():
+ return True
+ return False
+
+
+class RenderButtonsPanel:
+ """Use this class to define buttons from the render tab of
+ properties window."""
+
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "render"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ rd = context.scene.render
+ return rd.engine in cls.COMPAT_ENGINES
+
+
+class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
+ """Use this class to define pov ini settingss buttons."""
+
+ bl_options = {'DEFAULT_CLOSED'}
+ bl_label = "Auto Start"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw_header(self, context):
+ scene = context.scene
+ if scene.pov.tempfiles_enable:
+ self.layout.prop(scene.pov, "tempfiles_enable", text="", icon='AUTO')
+ else:
+ self.layout.prop(scene.pov, "tempfiles_enable", text="", icon='CONSOLE')
+
+ def draw(self, context):
+
+ layout = self.layout
+
+ scene = context.scene
+
+ layout.active = scene.pov.max_trace_level != 0
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Command line options:")
+ col.prop(scene.pov, "command_line_switches", text="", icon='RIGHTARROW')
+ split = layout.split()
+
+ # layout.active = not scene.pov.tempfiles_enable
+ if not scene.pov.tempfiles_enable:
+ split.prop(scene.pov, "deletefiles_enable", text="Delete files")
+ split.prop(scene.pov, "pov_editor", text="POV Editor")
+
+ col = layout.column()
+ col.prop(scene.pov, "scene_name", text="Name")
+ col.prop(scene.pov, "scene_path", text="Path to files")
+ # col.prop(scene.pov, "scene_path", text="Path to POV-file")
+ # col.prop(scene.pov, "renderimage_path", text="Path to image")
+
+ split = layout.split()
+ split.prop(scene.pov, "indentation_character", text="Indent")
+ if scene.pov.indentation_character == 'SPACE':
+ split.prop(scene.pov, "indentation_spaces", text="Spaces")
+
+ row = layout.row()
+ row.prop(scene.pov, "comments_enable", text="Comments")
+ row.prop(scene.pov, "list_lf_enable", text="Line breaks in lists")
+
+
+class RENDER_PT_POV_render_settings(RenderButtonsPanel, Panel):
+ """Use this class to define pov render settings buttons."""
+
+ bl_label = "Global Settings"
+ bl_icon = 'SETTINGS'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw_header(self, context):
+ scene = context.scene
+ if scene.pov.global_settings_advanced:
+ self.layout.prop(scene.pov, "global_settings_advanced", text="", icon='SETTINGS')
+ else:
+ self.layout.prop(scene.pov, "global_settings_advanced", text="", icon='PREFERENCES')
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ # rd = context.scene.render
+ # layout.active = (scene.pov.max_trace_level != 0)
+
+ if not platform.startswith('win'):
+ layout.prop(scene.pov, "sdl_window_enable", text="POV-Ray SDL Window")
+
+ col = layout.column()
+ col.label(text="Main Path Tracing:")
+ col.prop(scene.pov, "max_trace_level", text="Ray Depth")
+ align = True
+ layout.active = scene.pov.global_settings_advanced
+ row = layout.row(align=align)
+ row.prop(scene.pov, "adc_bailout")
+ row = layout.row(align=align)
+ row.prop(scene.pov, "ambient_light")
+ row = layout.row(align=align)
+ row.prop(scene.pov, "irid_wavelength")
+ row = layout.row(align=align)
+ row.prop(scene.pov, "number_of_waves")
+ row = layout.row(align=align)
+ row.prop(scene.pov, "noise_generator")
+
+ split = layout.split()
+ split.label(text="Shading:")
+ split = layout.split()
+
+ row = split.row(align=align)
+ row.prop(scene.pov, "use_shadows")
+ row.prop(scene.pov, "alpha_mode")
+
+
+class RENDER_PT_POV_photons(RenderButtonsPanel, Panel):
+ """Use this class to define pov photons buttons."""
+
+ bl_label = "Photons"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ # def draw_header(self, context):
+ # self.layout.label(icon='SETTINGS')
+
+ def draw_header(self, context):
+ scene = context.scene
+ if scene.pov.photon_enable:
+ self.layout.prop(scene.pov, "photon_enable", text="", icon='PMARKER_ACT')
+ else:
+ self.layout.prop(scene.pov, "photon_enable", text="", icon='PMARKER')
+
+ def draw(self, context):
+ scene = context.scene
+ layout = self.layout
+ layout.active = scene.pov.photon_enable
+ col = layout.column()
+ # col.label(text="Global Photons:")
+ col.prop(scene.pov, "photon_max_trace_level", text="Photon Depth")
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(scene.pov, "photon_spacing", text="Spacing")
+ col.prop(scene.pov, "photon_gather_min")
+
+ col = split.column()
+ col.prop(scene.pov, "photon_adc_bailout", text="Photon ADC")
+ col.prop(scene.pov, "photon_gather_max")
+
+ box = layout.box()
+ box.label(text='Photon Map File:')
+ row = box.row()
+ row.prop(scene.pov, "photon_map_file_save_load", expand=True)
+ if scene.pov.photon_map_file_save_load in {'save'}:
+ box.prop(scene.pov, "photon_map_dir")
+ box.prop(scene.pov, "photon_map_filename")
+ if scene.pov.photon_map_file_save_load in {'load'}:
+ box.prop(scene.pov, "photon_map_file")
+ # end main photons
+
+
+class RENDER_PT_POV_antialias(RenderButtonsPanel, Panel):
+ """Use this class to define pov antialiasing buttons."""
+
+ bl_label = "Anti-Aliasing"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw_header(self, context):
+ prefs = bpy.context.preferences.addons[__package__].preferences
+ scene = context.scene
+ if prefs.branch_feature_set_povray != 'uberpov' and scene.pov.antialias_method == '2':
+ self.layout.prop(scene.pov, "antialias_enable", text="", icon='ERROR')
+ elif scene.pov.antialias_enable:
+ self.layout.prop(scene.pov, "antialias_enable", text="", icon='ANTIALIASED')
+ else:
+ self.layout.prop(scene.pov, "antialias_enable", text="", icon='ALIASED')
+
+ def draw(self, context):
+ prefs = bpy.context.preferences.addons[__package__].preferences
+ layout = self.layout
+ scene = context.scene
+
+ layout.active = scene.pov.antialias_enable
+
+ row = layout.row()
+ row.prop(scene.pov, "antialias_method", text="")
+
+ if prefs.branch_feature_set_povray != 'uberpov' and scene.pov.antialias_method == '2':
+ col = layout.column()
+ col.alignment = 'CENTER'
+ col.label(text="Stochastic Anti Aliasing is")
+ col.label(text="Only Available with UberPOV")
+ col.label(text="Feature Set in User Preferences.")
+ col.label(text="Using Type 2 (recursive) instead")
+ else:
+ row.prop(scene.pov, "jitter_enable", text="Jitter")
+
+ split = layout.split()
+ col = split.column()
+ col.prop(scene.pov, "antialias_depth", text="AA Depth")
+ sub = split.column()
+ sub.prop(scene.pov, "jitter_amount", text="Jitter Amount")
+ if scene.pov.jitter_enable:
+ sub.enabled = True
+ else:
+ sub.enabled = False
+
+ row = layout.row()
+ row.prop(scene.pov, "antialias_threshold", text="AA Threshold")
+ row.prop(scene.pov, "antialias_gamma", text="AA Gamma")
+
+ if prefs.branch_feature_set_povray == 'uberpov':
+ row = layout.row()
+ row.prop(scene.pov, "antialias_confidence", text="AA Confidence")
+ if scene.pov.antialias_method == '2':
+ row.enabled = True
+ else:
+ row.enabled = False
+
+
+class RENDER_PT_POV_radiosity(RenderButtonsPanel, Panel):
+ """Use this class to define pov radiosity buttons."""
+
+ bl_label = "Diffuse Radiosity"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw_header(self, context):
+ scene = context.scene
+ if scene.pov.radio_enable:
+ self.layout.prop(scene.pov, "radio_enable", text="", icon='OUTLINER_OB_LIGHTPROBE')
+ else:
+ self.layout.prop(scene.pov, "radio_enable", text="", icon='LIGHTPROBE_CUBEMAP')
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+
+ layout.active = scene.pov.radio_enable
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(scene.pov, "radio_count", text="Rays")
+ col.prop(scene.pov, "radio_recursion_limit", text="Recursions")
+
+ split.prop(scene.pov, "radio_error_bound", text="Error Bound")
+
+ layout.prop(scene.pov, "radio_display_advanced")
+
+ if scene.pov.radio_display_advanced:
+ split = layout.split()
+
+ col = split.column()
+ col.prop(scene.pov, "radio_adc_bailout", slider=True)
+ col.prop(scene.pov, "radio_minimum_reuse", text="Min Reuse")
+ col.prop(scene.pov, "radio_gray_threshold", slider=True)
+ col.prop(scene.pov, "radio_pretrace_start", slider=True)
+ col.prop(scene.pov, "radio_low_error_factor", slider=True)
+
+ col = split.column()
+ col.prop(scene.pov, "radio_brightness")
+ col.prop(scene.pov, "radio_maximum_reuse", text="Max Reuse")
+ col.prop(scene.pov, "radio_nearest_count")
+ col.prop(scene.pov, "radio_pretrace_end", slider=True)
+
+ col = layout.column()
+ col.label(text="Estimation Influence:")
+ col.prop(scene.pov, "radio_always_sample")
+ col.prop(scene.pov, "radio_normal")
+ col.prop(scene.pov, "radio_media")
+ col.prop(scene.pov, "radio_subsurface")
+
+
+class POV_RADIOSITY_MT_presets(Menu):
+ """Use this class to define pov radiosity presets menu."""
+
+ bl_label = "Radiosity Presets"
+ preset_subdir = "pov/radiosity"
+ preset_operator = "script.execute_preset"
+ draw = bpy.types.Menu.draw_preset
+
+
+class RENDER_OT_POV_radiosity_add_preset(AddPresetBase, Operator):
+ """Use this class to define pov radiosity add presets button"""
+
+ '''Add a Radiosity Preset'''
+ bl_idname = "scene.radiosity_preset_add"
+ bl_label = "Add Radiosity Preset"
+ preset_menu = "POV_RADIOSITY_MT_presets"
+
+ # variable used for all preset values
+ preset_defines = ["scene = bpy.context.scene"]
+
+ # properties to store in the preset
+ preset_values = [
+ "scene.pov.radio_display_advanced",
+ "scene.pov.radio_adc_bailout",
+ "scene.pov.radio_always_sample",
+ "scene.pov.radio_brightness",
+ "scene.pov.radio_count",
+ "scene.pov.radio_error_bound",
+ "scene.pov.radio_gray_threshold",
+ "scene.pov.radio_low_error_factor",
+ "scene.pov.radio_media",
+ "scene.pov.radio_subsurface",
+ "scene.pov.radio_minimum_reuse",
+ "scene.pov.radio_maximum_reuse",
+ "scene.pov.radio_nearest_count",
+ "scene.pov.radio_normal",
+ "scene.pov.radio_recursion_limit",
+ "scene.pov.radio_pretrace_start",
+ "scene.pov.radio_pretrace_end",
+ ]
+
+ # where to store the preset
+ preset_subdir = "pov/radiosity"
+
+
+# Draw into an existing panel
+def rad_panel_func(self, context):
+ """Display radiosity presets rolldown menu"""
+ layout = self.layout
+
+ row = layout.row(align=True)
+ row.menu(POV_RADIOSITY_MT_presets.__name__, text=POV_RADIOSITY_MT_presets.bl_label)
+ row.operator(RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='ADD')
+ row.operator(
+ RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='REMOVE'
+ ).remove_active = True
+
+
+###############################################################################
+# Freestyle
+###############################################################################
+# import addon_utils
+# addon_utils.paths()[0]
+# addon_utils.modules()
+# mod.bl_info['name'] == 'Freestyle SVG Exporter':
+bpy.utils.script_paths("addons")
+# render_freestyle_svg = os.path.join(bpy.utils.script_paths("addons"), "render_freestyle_svg.py")
+
+render_freestyle_svg = bpy.context.preferences.addons.get('render_freestyle_svg')
+# mpath=addon_utils.paths()[0].render_freestyle_svg
+# import mpath
+# from mpath import render_freestyle_svg #= addon_utils.modules(['Freestyle SVG Exporter'])
+# from scripts\\addons import render_freestyle_svg
+if check_render_freestyle_svg():
+ '''
+ snippetsWIP
+ import myscript
+ import importlib
+
+ importlib.reload(myscript)
+ myscript.main()
+ '''
+ for member in dir(render_freestyle_svg):
+ subclass = getattr(render_freestyle_svg, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+ if subclass.bl_idname == "RENDER_PT_SVGExporterPanel":
+ subclass.bl_parent_id = "RENDER_PT_POV_filter"
+ subclass.bl_options = {'HIDE_HEADER'}
+ # subclass.bl_order = 11
+ print(subclass.bl_info)
+
+ # del render_freestyle_svg.RENDER_PT_SVGExporterPanel.bl_parent_id
+
+
+class RENDER_PT_POV_filter(RenderButtonsPanel, Panel):
+ """Use this class to invoke stuff like Freestyle UI."""
+
+ bl_label = "Freestyle"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ with_freestyle = bpy.app.build_options.freestyle
+ engine = context.scene.render.engine
+ return with_freestyle and engine == 'POVRAY_RENDER'
+
+ def draw_header(self, context):
+
+ # scene = context.scene
+ rd = context.scene.render
+ layout = self.layout
+
+ if rd.use_freestyle:
+ layout.prop(rd, "use_freestyle", text="", icon='LINE_DATA')
+
+ else:
+ layout.prop(rd, "use_freestyle", text="", icon='OUTLINER_OB_IMAGE')
+
+ def draw(self, context):
+ rd = context.scene.render
+ layout = self.layout
+ layout.active = rd.use_freestyle
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
+ flow = layout.grid_flow(
+ row_major=True, columns=0, even_columns=True, even_rows=False, align=True
+ )
+
+ flow.prop(rd, "line_thickness_mode", expand=True)
+
+ if rd.line_thickness_mode == 'ABSOLUTE':
+ flow.prop(rd, "line_thickness")
+
+ # Warning if the Freestyle SVG Exporter addon is not enabled
+ if not check_render_freestyle_svg():
+ # col = box.column()
+ layout.label(text="Please enable Freestyle SVG Exporter addon", icon="INFO")
+ # layout.separator()
+ layout.operator(
+ "preferences.addon_show",
+ text="Go to Render: Freestyle SVG Exporter addon",
+ icon="PREFERENCES",
+ ).module = "render_freestyle_svg"
+
+
+##class RENDER_PT_povray_baking(RenderButtonsPanel, Panel):
+## bl_label = "Baking"
+## COMPAT_ENGINES = {'POVRAY_RENDER'}
+##
+## def draw_header(self, context):
+## scene = context.scene
+##
+## self.layout.prop(scene.pov, "baking_enable", text="")
+##
+## def draw(self, context):
+## layout = self.layout
+##
+## scene = context.scene
+## rd = scene.render
+##
+## layout.active = scene.pov.baking_enable
+
+
+classes = (
+ RENDER_PT_POV_export_settings,
+ RENDER_PT_POV_render_settings,
+ RENDER_PT_POV_photons,
+ RENDER_PT_POV_antialias,
+ RENDER_PT_POV_radiosity,
+ RENDER_PT_POV_filter,
+ # RENDER_PT_povray_baking,
+ POV_RADIOSITY_MT_presets,
+ RENDER_OT_POV_radiosity_add_preset,
+)
+
+
+def register():
+ for cls in classes:
+ register_class(cls)
+ bpy.types.RENDER_PT_POV_radiosity.prepend(rad_panel_func)
+
+
+def unregister():
+ bpy.types.RENDER_PT_POV_radiosity.remove(rad_panel_func)
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/render_properties.py b/render_povray/render_properties.py
new file mode 100755
index 00000000..9096c986
--- /dev/null
+++ b/render_povray/render_properties.py
@@ -0,0 +1,687 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare rendering properties controllable in UI"""
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+ BoolProperty,
+ IntProperty,
+ FloatProperty,
+ FloatVectorProperty,
+ StringProperty,
+ EnumProperty,
+ PointerProperty,
+)
+
+###############################################################################
+# Scene POV properties.
+###############################################################################
+class RenderPovSettingsScene(PropertyGroup):
+
+ """Declare scene level properties controllable in UI and translated to POV"""
+
+ # Linux SDL-window enable
+ sdl_window_enable: BoolProperty(
+ name="Enable SDL window", description="Enable the SDL window in Linux OS", default=True
+ )
+ # File Options
+ text_block: StringProperty(
+ name="Text Scene Name",
+ description="Name of POV scene to use. "
+ "Set when clicking Run to render current text only",
+ maxlen=1024,
+ )
+ tempfiles_enable: BoolProperty(
+ name="Enable Tempfiles",
+ description="Enable the OS-Tempfiles. Otherwise set the path where to save the files",
+ default=True,
+ )
+ pov_editor: BoolProperty(
+ name="POV editor",
+ description="Don't Close POV editor after rendering (Overridden by /EXIT command)",
+ default=False,
+ )
+ deletefiles_enable: BoolProperty(
+ name="Delete files",
+ description="Delete files after rendering. Doesn't work with the image",
+ default=True,
+ )
+ scene_name: StringProperty(
+ name="Scene Name",
+ description="Name of POV scene to create. Empty name will use "
+ "the name of the blend file",
+ maxlen=1024,
+ )
+ scene_path: StringProperty(
+ name="Export scene path",
+ # Bug in POV-Ray RC3
+ # description="Path to directory where the exported scene "
+ # "(POV and INI) is created",
+ description="Path to directory where the files are created",
+ maxlen=1024,
+ subtype="DIR_PATH",
+ )
+ renderimage_path: StringProperty(
+ name="Rendered image path",
+ description="Full path to directory where the rendered image is saved",
+ maxlen=1024,
+ subtype="DIR_PATH",
+ )
+ list_lf_enable: BoolProperty(
+ name="LF in lists",
+ description="Enable line breaks in lists (vectors and indices). "
+ "Disabled: lists are exported in one line",
+ default=False,
+ )
+
+ # Not a real pov option, just to know if we should write
+ radio_enable: BoolProperty(
+ name="Enable Radiosity", description="Enable POV radiosity calculation", default=True
+ )
+
+ radio_display_advanced: BoolProperty(
+ name="Advanced Options", description="Show advanced options", default=False
+ )
+
+ media_enable: BoolProperty(
+ name="Enable Media", description="Enable POV atmospheric media", default=False
+ )
+
+ media_samples: IntProperty(
+ name="Samples",
+ description="Number of samples taken from camera to first object "
+ "encountered along ray path for media calculation",
+ min=1,
+ max=100,
+ default=35,
+ )
+
+ media_scattering_type: EnumProperty(
+ name="Scattering Type",
+ description="Scattering model",
+ items=(
+ (
+ "1",
+ "1 Isotropic",
+ "The simplest form of scattering because it is independent of direction.",
+ ),
+ (
+ "2",
+ "2 Mie haze ",
+ "For relatively small particles such as "
+ "minuscule water droplets of fog, cloud "
+ "particles, and particles responsible "
+ "for the polluted sky. In this model the"
+ " scattering is extremely directional in"
+ " the forward direction i.e. the amount "
+ "of scattered light is largest when the "
+ "incident light is anti-parallel to the "
+ "viewing direction (the light goes "
+ "directly to the viewer). It is smallest"
+ " when the incident light is parallel to"
+ " the viewing direction. ",
+ ),
+ ("3", "3 Mie murky", "Like haze but much more directional"),
+ (
+ "4",
+ "4 Rayleigh",
+ "For extremely small particles such as "
+ "molecules of the air. The amount of "
+ "scattered light depends on the incident"
+ " light angle. It is largest when the "
+ "incident light is parallel or "
+ "anti-parallel to the viewing direction "
+ "and smallest when the incident light is "
+ "perpendicular to viewing direction.",
+ ),
+ (
+ "5",
+ "5 Henyey-Greenstein",
+ "The default eccentricity value "
+ "of zero defines isotropic "
+ "scattering while positive "
+ "values lead to scattering in "
+ "the direction of the light and "
+ "negative values lead to "
+ "scattering in the opposite "
+ "direction of the light. Larger "
+ "values of e (or smaller values "
+ "in the negative case) increase "
+ "the directional property of the"
+ " scattering.",
+ ),
+ ),
+ default="1",
+ )
+
+ media_diffusion_scale: FloatProperty(
+ name="Scale",
+ description="Scale factor of Media Diffusion Color",
+ precision=6,
+ step=0.00000001,
+ min=0.000000001,
+ max=1.0,
+ default=(1.0),
+ )
+
+ media_diffusion_color: FloatVectorProperty(
+ name="Media Diffusion Color",
+ description="The atmospheric media color",
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(0.001, 0.001, 0.001),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ media_absorption_scale: FloatProperty(
+ name="Scale",
+ description="Scale factor of Media Absorption Color. "
+ "use 1/depth of media volume in meters",
+ precision=6,
+ step=0.000001,
+ min=0.000000001,
+ max=1.0,
+ default=(0.00002),
+ )
+
+ media_absorption_color: FloatVectorProperty(
+ name="Media Absorption Color",
+ description="The atmospheric media absorption color",
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(0.0, 0.0, 0.0),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ media_eccentricity: FloatProperty(
+ name="Media Eccenticity Factor",
+ description="Positive values lead"
+ " to scattering in the direction of the light and negative "
+ "values lead to scattering in the opposite direction of the "
+ "light. Larger values of e (or smaller values in the negative"
+ " case) increase the directional property of the scattering",
+ precision=2,
+ step=0.01,
+ min=-1.0,
+ max=1.0,
+ default=(0.0),
+ options={"ANIMATABLE"},
+ )
+
+ baking_enable: BoolProperty(
+ name="Enable Baking", description="Enable POV texture baking", default=False
+ )
+
+ indentation_character: EnumProperty(
+ name="Indentation",
+ description="Select the indentation type",
+ items=(
+ ("NONE", "None", "No indentation"),
+ ("TAB", "Tabs", "Indentation with tabs"),
+ ("SPACE", "Spaces", "Indentation with spaces"),
+ ),
+ default="SPACE",
+ )
+
+ indentation_spaces: IntProperty(
+ name="Quantity of spaces",
+ description="The number of spaces for indentation",
+ min=1,
+ max=10,
+ default=4,
+ )
+
+ comments_enable: BoolProperty(
+ name="Enable Comments", description="Add comments to pov file", default=True
+ )
+
+ # Real pov options
+ command_line_switches: StringProperty(
+ name="Command Line Switches",
+ description="Command line switches consist of a + (plus) or - "
+ "(minus) sign, followed by one or more alphabetic "
+ "characters and possibly a numeric value",
+ maxlen=500,
+ )
+
+ antialias_enable: BoolProperty(
+ name="Anti-Alias", description="Enable Anti-Aliasing", default=True
+ )
+
+ antialias_method: EnumProperty(
+ name="Method",
+ description="AA-sampling method. Type 1 is an adaptive, "
+ "non-recursive, super-sampling (as in the plain old render "
+ "bigger and scale down trick. Type 2 is a slightly "
+ "more efficient adaptive and recursive super-sampling. "
+ "Type 3 is a stochastic halton based super-sampling method so "
+ "rather artifact free and sampling rays so depth of field can "
+ "use them at no additional cost, as do area lights and "
+ "subsurface scattering materials, making it the best "
+ "quality / time trade-off in complex scenes",
+ items=(
+ ("0", "non-recursive AA", "Type 1 Sampling in POV"),
+ ("1", "recursive AA", "Type 2 Sampling in POV"),
+ ("2", "stochastic AA", "Type 3 Sampling in POV"),
+ ),
+ default="1",
+ )
+
+ antialias_confidence: FloatProperty(
+ name="Antialias Confidence",
+ description="how surely the computed color "
+ "of a given pixel is indeed"
+ "within the threshold error margin",
+ min=0.0001,
+ max=1.0000,
+ default=0.9900,
+ precision=4,
+ )
+
+ antialias_depth: IntProperty(
+ name="Antialias Depth", description="Depth of pixel for sampling", min=1, max=9, default=2
+ )
+
+ antialias_threshold: FloatProperty(
+ name="Antialias Threshold",
+ description="Tolerance for sub-pixels",
+ min=0.0,
+ max=1.0,
+ soft_min=0.05,
+ soft_max=0.5,
+ default=0.03,
+ )
+
+ jitter_enable: BoolProperty(
+ name="Jitter",
+ description="Enable Jittering. Adds noise into the sampling "
+ "process (it should be avoided to use jitter in "
+ "animation)",
+ default=False,
+ )
+
+ jitter_amount: FloatProperty(
+ name="Jitter Amount",
+ description="Amount of jittering",
+ min=0.0,
+ max=1.0,
+ soft_min=0.01,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+ antialias_gamma: FloatProperty(
+ name="Antialias Gamma",
+ description="POV-Ray compares gamma-adjusted values for super "
+ "sampling. Antialias Gamma sets the Gamma before "
+ "comparison",
+ min=0.0,
+ max=5.0,
+ soft_min=0.01,
+ soft_max=2.5,
+ default=2.5,
+ )
+
+ alpha_mode: EnumProperty(
+ name="Alpha",
+ description="Representation of alpha information in the RGBA pixels",
+ items=(
+ ("SKY", "Sky", "Transparent pixels are filled with sky color"),
+ (
+ "TRANSPARENT",
+ "Transparent",
+ "Transparent, World background is transparent with premultiplied alpha",
+ ),
+ ),
+ default="SKY",
+ )
+
+ use_shadows: BoolProperty(
+ name="Shadows", description="Calculate shadows while rendering", default=True
+ )
+
+ max_trace_level: IntProperty(
+ name="Max Trace Level",
+ description="Number of reflections/refractions allowed on ray " "path",
+ min=1,
+ max=256,
+ default=5,
+ )
+
+ adc_bailout_enable: BoolProperty(name="Enable", description="", default=False)
+
+ adc_bailout: FloatProperty(
+ name="ADC Bailout",
+ description="Adaptive Depth Control (ADC) to stop computing additional"
+ "reflected or refracted rays when their contribution is insignificant."
+ "The default value is 1/255, or approximately 0.0039, since a change "
+ "smaller than that could not be visible in a 24 bit image. Generally "
+ "this value is fine and should be left alone."
+ "Setting adc_bailout to 0 will disable ADC, relying completely on "
+ "max_trace_level to set an upper limit on the number of rays spawned. ",
+ min=0.0,
+ max=1000.0,
+ default=0.00392156862745,
+ precision=3,
+ )
+
+ ambient_light_enable: BoolProperty(name="Enable", description="", default=False)
+
+ ambient_light: FloatVectorProperty(
+ name="Ambient Light",
+ description="Ambient light is used to simulate the effect of inter-diffuse reflection",
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(1, 1, 1),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+ global_settings_advanced: BoolProperty(name="Advanced", description="", default=False)
+
+ irid_wavelength_enable: BoolProperty(name="Enable", description="", default=False)
+
+ irid_wavelength: FloatVectorProperty(
+ name="Irid Wavelength",
+ description=(
+ "Iridescence calculations depend upon the dominant "
+ "wavelengths of the primary colors of red, green and blue light"
+ ),
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(0.25, 0.18, 0.14),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ number_of_waves_enable: BoolProperty(name="Enable", description="", default=False)
+
+ number_of_waves: IntProperty(
+ name="Number Waves",
+ description=(
+ "The waves and ripples patterns are generated by summing a series of waves, "
+ "each with a slightly different center and size"
+ ),
+ min=1,
+ max=10,
+ default=1000,
+ )
+
+ noise_generator_enable: BoolProperty(name="Enable", description="", default=False)
+
+ noise_generator: IntProperty(
+ name="Noise Generator",
+ description="There are three noise generators implemented",
+ min=1,
+ max=3,
+ default=2,
+ )
+
+ ########################### PHOTONS #######################################
+ photon_enable: BoolProperty(name="Photons", description="Enable global photons", default=False)
+
+ photon_enable_count: BoolProperty(
+ name="Spacing / Count", description="Enable count photons", default=False
+ )
+
+ photon_count: IntProperty(
+ name="Count", description="Photons count", min=1, max=100000000, default=20000
+ )
+
+ photon_spacing: FloatProperty(
+ name="Spacing",
+ description="Average distance between photons on surfaces. half "
+ "this get four times as many surface photons",
+ min=0.001,
+ max=1.000,
+ soft_min=0.001,
+ soft_max=1.000,
+ precision=3,
+ default=0.005,
+ )
+
+ photon_max_trace_level: IntProperty(
+ name="Max Trace Level",
+ description="Number of reflections/refractions allowed on ray " "path",
+ min=1,
+ max=256,
+ default=5,
+ )
+
+ photon_adc_bailout: FloatProperty(
+ name="ADC Bailout",
+ description="The adc_bailout for photons. Use adc_bailout = "
+ "0.01 / brightest_ambient_object for good results",
+ min=0.0,
+ max=1000.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ precision=3,
+ default=0.1,
+ )
+
+ photon_gather_min: IntProperty(
+ name="Gather Min",
+ description="Minimum number of photons gathered" "for each point",
+ min=1,
+ max=256,
+ default=20,
+ )
+
+ photon_gather_max: IntProperty(
+ name="Gather Max",
+ description="Maximum number of photons gathered for each point",
+ min=1,
+ max=256,
+ default=100,
+ )
+
+ photon_map_file_save_load: EnumProperty(
+ name="Operation",
+ description="Load or Save photon map file",
+ items=(("NONE", "None", ""), ("save", "Save", ""), ("load", "Load", "")),
+ default="NONE",
+ )
+
+ photon_map_filename: StringProperty(name="Filename", description="", maxlen=1024)
+
+ photon_map_dir: StringProperty(
+ name="Directory", description="", maxlen=1024, subtype="DIR_PATH"
+ )
+
+ photon_map_file: StringProperty(name="File", description="", maxlen=1024, subtype="FILE_PATH")
+
+ #########RADIOSITY########
+ radio_adc_bailout: FloatProperty(
+ name="ADC Bailout",
+ description="The adc_bailout for radiosity rays. Use "
+ "adc_bailout = 0.01 / brightest_ambient_object for good results",
+ min=0.0,
+ max=1000.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=0.0039,
+ precision=4,
+ )
+
+ radio_always_sample: BoolProperty(
+ name="Always Sample",
+ description="Only use the data from the pretrace step and not gather "
+ "any new samples during the final radiosity pass",
+ default=False,
+ )
+
+ radio_brightness: FloatProperty(
+ name="Brightness",
+ description="Amount objects are brightened before being returned "
+ "upwards to the rest of the system",
+ min=0.0,
+ max=1000.0,
+ soft_min=0.0,
+ soft_max=10.0,
+ default=1.0,
+ )
+
+ radio_count: IntProperty(
+ name="Ray Count",
+ description="Number of rays for each new radiosity value to be calculated "
+ "(halton sequence over 1600)",
+ min=1,
+ max=10000,
+ soft_max=1600,
+ default=35,
+ )
+
+ radio_error_bound: FloatProperty(
+ name="Error Bound",
+ description="One of the two main speed/quality tuning values, "
+ "lower values are more accurate",
+ min=0.0,
+ max=1000.0,
+ soft_min=0.1,
+ soft_max=10.0,
+ default=10.0,
+ )
+
+ radio_gray_threshold: FloatProperty(
+ name="Gray Threshold",
+ description="One of the two main speed/quality tuning values, "
+ "lower values are more accurate",
+ min=0.0,
+ max=1.0,
+ soft_min=0,
+ soft_max=1,
+ default=0.0,
+ )
+
+ radio_low_error_factor: FloatProperty(
+ name="Low Error Factor",
+ description="Just enough samples is slightly blotchy. Low error changes error "
+ "tolerance for less critical last refining pass",
+ min=0.000001,
+ max=1.0,
+ soft_min=0.000001,
+ soft_max=1.0,
+ default=0.5,
+ )
+
+ radio_media: BoolProperty(
+ name="Media", description="Radiosity estimation can be affected by media", default=True
+ )
+
+ radio_subsurface: BoolProperty(
+ name="Subsurface",
+ description="Radiosity estimation can be affected by Subsurface Light Transport",
+ default=False,
+ )
+
+ radio_minimum_reuse: FloatProperty(
+ name="Minimum Reuse",
+ description="Fraction of the screen width which sets the minimum radius of reuse "
+ "for each sample point (At values higher than 2% expect errors)",
+ min=0.0,
+ max=1.0,
+ soft_min=0.1,
+ soft_max=0.1,
+ default=0.015,
+ precision=3,
+ )
+
+ radio_maximum_reuse: FloatProperty(
+ name="Maximum Reuse",
+ description="The maximum reuse parameter works in conjunction with, and is similar to that of minimum reuse, "
+ "the only difference being that it is an upper bound rather than a lower one",
+ min=0.0,
+ max=1.0,
+ default=0.2,
+ precision=3,
+ )
+
+ radio_nearest_count: IntProperty(
+ name="Nearest Count",
+ description="Number of old ambient values blended together to "
+ "create a new interpolated value",
+ min=1,
+ max=20,
+ default=1,
+ )
+
+ radio_normal: BoolProperty(
+ name="Normals", description="Radiosity estimation can be affected by normals", default=False
+ )
+
+ radio_recursion_limit: IntProperty(
+ name="Recursion Limit",
+ description="how many recursion levels are used to calculate "
+ "the diffuse inter-reflection",
+ min=1,
+ max=20,
+ default=1,
+ )
+
+ radio_pretrace_start: FloatProperty(
+ name="Pretrace Start",
+ description="Fraction of the screen width which sets the size of the "
+ "blocks in the mosaic preview first pass",
+ min=0.005,
+ max=1.00,
+ soft_min=0.02,
+ soft_max=1.0,
+ default=0.04,
+ )
+ # XXX TODO set automatically to pretrace_end = 8 / max (image_width, image_height)
+ # for non advanced mode
+ radio_pretrace_end: FloatProperty(
+ name="Pretrace End",
+ description="Fraction of the screen width which sets the size of the blocks "
+ "in the mosaic preview last pass",
+ min=0.000925,
+ max=1.00,
+ soft_min=0.01,
+ soft_max=1.00,
+ default=0.004,
+ precision=3,
+ )
+
+
+classes = (RenderPovSettingsScene,)
+
+
+def register():
+ for cls in classes:
+ register_class(cls)
+ bpy.types.Scene.pov = PointerProperty(type=RenderPovSettingsScene)
+
+
+def unregister():
+ del bpy.types.Scene.pov
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/scenography.py b/render_povray/scenography.py
new file mode 100755
index 00000000..4b0c99e3
--- /dev/null
+++ b/render_povray/scenography.py
@@ -0,0 +1,847 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""With respect to camera frame and optics distortions, also export environment
+
+with world, sky, atmospheric effects such as rainbows or smoke """
+
+import bpy
+from bpy.utils import register_class, unregister_class
+import os
+from imghdr import what # imghdr is a python lib to identify image file types
+from math import atan, pi, sqrt, degrees
+from . import df3_library # for smoke rendering
+from .object_primitives import write_object_modifiers
+
+##############find image texture # used for export_world
+def image_format(imgF):
+ """Identify input image filetypes to transmit to POV."""
+ # First use the below explicit extensions to identify image file prospects
+ ext = {
+ 'JPG': "jpeg",
+ 'JPEG': "jpeg",
+ 'GIF': "gif",
+ 'TGA': "tga",
+ 'IFF': "iff",
+ 'PPM': "ppm",
+ 'PNG': "png",
+ 'SYS': "sys",
+ 'TIFF': "tiff",
+ 'TIF': "tiff",
+ 'EXR': "exr",
+ 'HDR': "hdr",
+ }.get(os.path.splitext(imgF)[-1].upper(), "")
+ # Then, use imghdr to really identify the filetype as it can be different
+ if not ext:
+ # maybe add a check for if path exists here?
+ print(" WARNING: texture image has no extension") # too verbose
+
+ ext = what(imgF) # imghdr is a python lib to identify image file types
+ return ext
+
+
+def img_map(ts):
+ """Translate mapping type from Blender UI to POV syntax and return that string."""
+ image_map = ""
+ texdata = bpy.data.textures[ts.texture]
+ if ts.mapping == 'FLAT':
+ image_map = "map_type 0 "
+ elif ts.mapping == 'SPHERE':
+ image_map = "map_type 1 "
+ elif ts.mapping == 'TUBE':
+ image_map = "map_type 2 "
+
+ ## map_type 3 and 4 in development (?) (ENV in pov 3.8)
+ ## for POV-Ray, currently they just seem to default back to Flat (type 0)
+ # elif ts.mapping=="?":
+ # image_map = " map_type 3 "
+ # elif ts.mapping=="?":
+ # image_map = " map_type 4 "
+ if ts.use_interpolation: # Available if image sampling class reactivated?
+ image_map += " interpolate 2 "
+ if texdata.extension == 'CLIP':
+ image_map += " once "
+ # image_map += "}"
+ # if ts.mapping=='CUBE':
+ # image_map+= "warp { cubic } rotate <-90,0,180>"
+ # no direct cube type mapping. Though this should work in POV 3.7
+ # it doesn't give that good results(best suited to environment maps?)
+ # if image_map == "":
+ # print(" No texture image found ")
+ return image_map
+
+
+def img_map_transforms(ts):
+ """Translate mapping transformations from Blender UI to POV syntax and return that string."""
+ # XXX TODO: unchecked textures give error of variable referenced before assignment XXX
+ # POV-Ray "scale" is not a number of repetitions factor, but ,its
+ # inverse, a standard scale factor.
+ # 0.5 Offset is needed relatively to scale because center of the
+ # scale is 0.5,0.5 in blender and 0,0 in POV
+ # Strange that the translation factor for scale is not the same as for
+ # translate.
+ # TODO: verify both matches with other blender renderers / internal in previous versions.
+ image_map_transforms = ""
+ image_map_transforms = "scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % (
+ ts.scale[0],
+ ts.scale[1],
+ ts.scale[2],
+ ts.offset[0],
+ ts.offset[1],
+ ts.offset[2],
+ )
+ # image_map_transforms = (" translate <-0.5,-0.5,0.0> scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
+ # ( 1.0 / ts.scale.x,
+ # 1.0 / ts.scale.y,
+ # 1.0 / ts.scale.z,
+ # (0.5 / ts.scale.x) + ts.offset.x,
+ # (0.5 / ts.scale.y) + ts.offset.y,
+ # ts.offset.z))
+ # image_map_transforms = (
+ # "translate <-0.5,-0.5,0> "
+ # "scale <-1,-1,1> * <%.4g,%.4g,%.4g> "
+ # "translate <0.5,0.5,0> + <%.4g,%.4g,%.4g>" % \
+ # (1.0 / ts.scale.x,
+ # 1.0 / ts.scale.y,
+ # 1.0 / ts.scale.z,
+ # ts.offset.x,
+ # ts.offset.y,
+ # ts.offset.z)
+ # )
+ return image_map_transforms
+
+
+def img_map_bg(wts):
+ """Translate world mapping from Blender UI to POV syntax and return that string."""
+ tex = bpy.data.textures[wts.texture]
+ image_mapBG = ""
+ # texture_coords refers to the mapping of world textures:
+ if wts.texture_coords == 'VIEW' or wts.texture_coords == 'GLOBAL':
+ image_mapBG = " map_type 0 "
+ elif wts.texture_coords == 'ANGMAP':
+ image_mapBG = " map_type 1 "
+ elif wts.texture_coords == 'TUBE':
+ image_mapBG = " map_type 2 "
+
+ if tex.use_interpolation:
+ image_mapBG += " interpolate 2 "
+ if tex.extension == 'CLIP':
+ image_mapBG += " once "
+ # image_mapBG += "}"
+ # if wts.mapping == 'CUBE':
+ # image_mapBG += "warp { cubic } rotate <-90,0,180>"
+ # no direct cube type mapping. Though this should work in POV 3.7
+ # it doesn't give that good results(best suited to environment maps?)
+ # if image_mapBG == "":
+ # print(" No background texture image found ")
+ return image_mapBG
+
+
+def path_image(image):
+ """Conform a path string to POV syntax to avoid POV errors."""
+ return bpy.path.abspath(image.filepath, library=image.library).replace("\\", "/")
+ # .replace("\\","/") to get only forward slashes as it's what POV prefers,
+ # even on windows
+
+
+# end find image texture
+# -----------------------------------------------------------------------------
+
+
+def export_camera(scene, global_matrix, render, tab_write):
+ """Translate camera from Blender UI to POV syntax and write to exported file."""
+ camera = scene.camera
+
+ # DH disabled for now, this isn't the correct context
+ active_object = None # bpy.context.active_object # does not always work MR
+ matrix = global_matrix @ camera.matrix_world
+ focal_point = camera.data.dof.focus_distance
+
+ # compute resolution
+ q_size = render.resolution_x / render.resolution_y
+ tab_write("#declare camLocation = <%.6f, %.6f, %.6f>;\n" % matrix.translation[:])
+ tab_write(
+ "#declare camLookAt = <%.6f, %.6f, %.6f>;\n"
+ % tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
+ )
+
+ tab_write("camera {\n")
+ if scene.pov.baking_enable and active_object and active_object.type == 'MESH':
+ tab_write("mesh_camera{ 1 3\n") # distribution 3 is what we want here
+ tab_write("mesh{%s}\n" % active_object.name)
+ tab_write("}\n")
+ tab_write("location <0,0,.01>")
+ tab_write("direction <0,0,-1>")
+
+ else:
+ if camera.data.type == 'ORTHO':
+ # todo: track when SensorHeightRatio was added to see if needed (not used)
+ sensor_height_ratio = (
+ render.resolution_x * camera.data.ortho_scale / render.resolution_y
+ )
+ tab_write("orthographic\n")
+ # Blender angle is radian so should be converted to degrees:
+ # % (camera.data.angle * (180.0 / pi) )
+ # but actually argument is not compulsory after angle in pov ortho mode
+ tab_write("angle\n")
+ tab_write("right <%6f, 0, 0>\n" % -camera.data.ortho_scale)
+ tab_write("location <0, 0, 0>\n")
+ tab_write("look_at <0, 0, -1>\n")
+ tab_write("up <0, %6f, 0>\n" % (camera.data.ortho_scale / q_size))
+
+ elif camera.data.type == 'PANO':
+ tab_write("panoramic\n")
+ tab_write("location <0, 0, 0>\n")
+ tab_write("look_at <0, 0, -1>\n")
+ tab_write("right <%s, 0, 0>\n" % -q_size)
+ tab_write("up <0, 1, 0>\n")
+ tab_write("angle %f\n" % (360.0 * atan(16.0 / camera.data.lens) / pi))
+ elif camera.data.type == 'PERSP':
+ # Standard camera otherwise would be default in pov
+ tab_write("location <0, 0, 0>\n")
+ tab_write("look_at <0, 0, -1>\n")
+ tab_write("right <%s, 0, 0>\n" % -q_size)
+ tab_write("up <0, 1, 0>\n")
+ tab_write(
+ "angle %f\n"
+ % (2 * atan(camera.data.sensor_width / 2 / camera.data.lens) * 180.0 / pi)
+ )
+
+ tab_write(
+ "rotate <%.6f, %.6f, %.6f>\n" % tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
+ )
+ tab_write("translate <%.6f, %.6f, %.6f>\n" % matrix.translation[:])
+ if camera.data.dof.use_dof and (focal_point != 0 or camera.data.dof.focus_object):
+ tab_write("aperture %.3g\n" % (1 / (camera.data.dof.aperture_fstop * 10000) * 1000))
+ tab_write(
+ "blur_samples %d %d\n"
+ % (camera.data.pov.dof_samples_min, camera.data.pov.dof_samples_max)
+ )
+ tab_write("variance 1/%d\n" % camera.data.pov.dof_variance)
+ tab_write("confidence %.3g\n" % camera.data.pov.dof_confidence)
+ if camera.data.dof.focus_object:
+ focal_ob = scene.objects[camera.data.dof.focus_object.name]
+ matrix_blur = global_matrix @ focal_ob.matrix_world
+ tab_write("focal_point <%.4f,%.4f,%.4f>\n" % matrix_blur.translation[:])
+ else:
+ tab_write("focal_point <0, 0, %f>\n" % focal_point)
+ if camera.data.pov.normal_enable:
+ tab_write(
+ "normal {%s %.4f turbulence %.4f scale %.4f}\n"
+ % (
+ camera.data.pov.normal_patterns,
+ camera.data.pov.cam_normal,
+ camera.data.pov.turbulence,
+ camera.data.pov.scale,
+ )
+ )
+ tab_write("}\n")
+
+
+exported_lights_count = 0
+
+
+def export_lights(lamps, file, scene, global_matrix, write_matrix, tab_write):
+ """Translate lights from Blender UI to POV syntax and write to exported file."""
+
+ # Incremented after each lamp export to declare its target
+ # currently used for Fresnel diffuse shader as their slope vector:
+ global exported_lights_count
+ exported_lights_count = 0
+ # Get all lamps
+ for ob in lamps:
+ lamp = ob.data
+
+ matrix = global_matrix @ ob.matrix_world
+
+ # Color is no longer modified by energy
+ # any way to directly get bpy_prop_array as tuple?
+ color = tuple(lamp.color)
+
+ tab_write("light_source {\n")
+ tab_write("< 0,0,0 >\n")
+ tab_write("color srgb<%.3g, %.3g, %.3g>\n" % color)
+
+ if lamp.type == 'POINT':
+ pass
+ elif lamp.type == 'SPOT':
+ tab_write("spotlight\n")
+
+ # Falloff is the main radius from the centre line
+ tab_write("falloff %.2f\n" % (degrees(lamp.spot_size) / 2.0)) # 1 TO 179 FOR BOTH
+ tab_write("radius %.6f\n" % ((degrees(lamp.spot_size) / 2.0) * (1.0 - lamp.spot_blend)))
+
+ # Blender does not have a tightness equivalent, 0 is most like blender default.
+ tab_write("tightness 0\n") # 0:10f
+
+ tab_write("point_at <0, 0, -1>\n")
+ if lamp.pov.use_halo:
+ tab_write("looks_like{\n")
+ tab_write("sphere{<0,0,0>,%.6f\n" % lamp.distance)
+ tab_write("hollow\n")
+ tab_write("material{\n")
+ tab_write("texture{\n")
+ tab_write("pigment{rgbf<1,1,1,%.4f>}\n" % (lamp.pov.halo_intensity * 5.0))
+ tab_write("}\n")
+ tab_write("interior{\n")
+ tab_write("media{\n")
+ tab_write("emission 1\n")
+ tab_write("scattering {1, 0.5}\n")
+ tab_write("density{\n")
+ tab_write("spherical\n")
+ tab_write("color_map{\n")
+ tab_write("[0.0 rgb <0,0,0>]\n")
+ tab_write("[0.5 rgb <1,1,1>]\n")
+ tab_write("[1.0 rgb <1,1,1>]\n")
+ tab_write("}\n")
+ tab_write("}\n")
+ tab_write("}\n")
+ tab_write("}\n")
+ tab_write("}\n")
+ tab_write("}\n")
+ tab_write("}\n")
+ elif lamp.type == 'SUN':
+ tab_write("parallel\n")
+ tab_write("point_at <0, 0, -1>\n") # *must* be after 'parallel'
+
+ elif lamp.type == 'AREA':
+ tab_write("fade_distance %.6f\n" % (lamp.distance / 2.0))
+ # Area lights have no falloff type, so always use blenders lamp quad equivalent
+ # for those?
+ tab_write("fade_power %d\n" % 2)
+ size_x = lamp.size
+ samples_x = lamp.pov.shadow_ray_samples_x
+ if lamp.shape == 'SQUARE':
+ size_y = size_x
+ samples_y = samples_x
+ else:
+ size_y = lamp.size_y
+ samples_y = lamp.pov.shadow_ray_samples_y
+
+ tab_write(
+ "area_light <%.6f,0,0>,<0,%.6f,0> %d, %d\n" % (size_x, size_y, samples_x, samples_y)
+ )
+ tab_write("area_illumination\n")
+ if lamp.pov.shadow_ray_sample_method == 'CONSTANT_JITTERED':
+ if lamp.pov.use_jitter:
+ tab_write("jitter\n")
+ else:
+ tab_write("adaptive 1\n")
+ tab_write("jitter\n")
+
+ # No shadow checked either at global or light level:
+ if not scene.pov.use_shadows or (lamp.pov.shadow_method == 'NOSHADOW'):
+ tab_write("shadowless\n")
+
+ # Sun shouldn't be attenuated. Area lights have no falloff attribute so they
+ # are put to type 2 attenuation a little higher above.
+ if lamp.type not in {'SUN', 'AREA'}:
+ if lamp.falloff_type == 'INVERSE_SQUARE':
+ tab_write("fade_distance %.6f\n" % (sqrt(lamp.distance / 2.0)))
+ tab_write("fade_power %d\n" % 2) # Use blenders lamp quad equivalent
+ elif lamp.falloff_type == 'INVERSE_LINEAR':
+ tab_write("fade_distance %.6f\n" % (lamp.distance / 2.0))
+ tab_write("fade_power %d\n" % 1) # Use blenders lamp linear
+ elif lamp.falloff_type == 'CONSTANT':
+ tab_write("fade_distance %.6f\n" % (lamp.distance / 2.0))
+ tab_write("fade_power %d\n" % 3)
+ # Use blenders lamp constant equivalent no attenuation.
+ # Using Custom curve for fade power 3 for now.
+ elif lamp.falloff_type == 'CUSTOM_CURVE':
+ tab_write("fade_power %d\n" % 4)
+
+ write_matrix(matrix)
+
+ tab_write("}\n")
+
+ exported_lights_count += 1
+
+ # v(A,B) rotates vector A about origin by vector B.
+ file.write(
+ "#declare lampTarget%s= vrotate(<%.4g,%.4g,%.4g>,<%.4g,%.4g,%.4g>);\n"
+ % (
+ exported_lights_count,
+ -(ob.location.x),
+ -(ob.location.y),
+ -(ob.location.z),
+ ob.rotation_euler.x,
+ ob.rotation_euler.y,
+ ob.rotation_euler.z,
+ )
+ )
+
+
+def export_world(world, scene, global_matrix, tab_write):
+ """write world as POV backgrounbd and sky_sphere to exported file """
+ render = scene.pov
+ camera = scene.camera
+ matrix = global_matrix @ camera.matrix_world # view dependant for later use
+ if not world:
+ return
+ #############Maurice####################################
+ # These lines added to get sky gradient (visible with PNG output)
+ if world:
+ # For simple flat background:
+ if not world.pov.use_sky_blend:
+ # Non fully transparent background could premultiply alpha and avoid anti-aliasing
+ # display issue:
+ if render.alpha_mode == 'TRANSPARENT':
+ tab_write(
+ "background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n" % (world.pov.horizon_color[:])
+ )
+ # Currently using no alpha with Sky option:
+ elif render.alpha_mode == 'SKY':
+ tab_write("background {rgbt<%.3g, %.3g, %.3g, 0>}\n" % (world.pov.horizon_color[:]))
+ # StraightAlpha:
+ # XXX Does not exists anymore
+ # else:
+ # tab_write("background {rgbt<%.3g, %.3g, %.3g, 1>}\n" % (world.pov.horizon_color[:]))
+
+ world_tex_count = 0
+ # For Background image textures
+ for t in world.pov_texture_slots: # risk to write several sky_spheres but maybe ok.
+ if t:
+ tex = bpy.data.textures[t.texture]
+ if tex.type is not None:
+ world_tex_count += 1
+ # XXX No enable checkbox for world textures yet (report it?)
+ # if t and tex.type == 'IMAGE' and t.use:
+ if tex.type == 'IMAGE':
+ image_filename = path_image(tex.image)
+ if tex.image.filepath != image_filename:
+ tex.image.filepath = image_filename
+ if image_filename != "" and t.use_map_blend:
+ textures_blend = 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.pov.org/pov.newusers/thread/%3Cweb.4a5cddf4e9c9822ba2f93e20@news.pov.org%3E/
+ # Replace 4/3 by the ratio of each image found by some custom or existing
+ # function
+ # mapping_blend = (" 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))
+ # using camera rotation valuesdirectly from blender seems much easier
+ if t_blend.texture_coords == 'ANGMAP':
+ mapping_blend = ""
+ else:
+ # POV-Ray "scale" is not a number of repetitions factor, but its
+ # inverse, a standard scale factor.
+ # 0.5 Offset is needed relatively to scale because center of the
+ # UV scale is 0.5,0.5 in blender and 0,0 in POV
+ # Further Scale by 2 and translate by -1 are
+ # required for the sky_sphere not to repeat
+
+ mapping_blend = (
+ "scale 2 scale <%.4g,%.4g,%.4g> translate -1 "
+ "translate <%.4g,%.4g,%.4g> rotate<0,0,0> "
+ % (
+ (1.0 / t_blend.scale.x),
+ (1.0 / t_blend.scale.y),
+ (1.0 / t_blend.scale.z),
+ 0.5 - (0.5 / t_blend.scale.x) - t_blend.offset.x,
+ 0.5 - (0.5 / t_blend.scale.y) - t_blend.offset.y,
+ t_blend.offset.z,
+ )
+ )
+
+ # 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.
+ tab_write("sky_sphere {\n")
+ tab_write("pigment {\n")
+ tab_write(
+ "image_map{%s \"%s\" %s}\n"
+ % (image_format(textures_blend), textures_blend, img_map_bg(t_blend))
+ )
+ tab_write("}\n")
+ tab_write("%s\n" % (mapping_blend))
+ # The following layered pigment opacifies to black over the texture for
+ # transmit below 1 or otherwise adds to itself
+ tab_write("pigment {rgb 0 transmit %s}\n" % (tex.intensity))
+ tab_write("}\n")
+ # tab_write("scale 2\n")
+ # tab_write("translate -1\n")
+
+ # For only Background gradient
+
+ if world_tex_count == 0:
+ if world.pov.use_sky_blend:
+ tab_write("sky_sphere {\n")
+ tab_write("pigment {\n")
+ # maybe Should follow the advice of POV doc about replacing gradient
+ # for skysphere..5.5
+ tab_write("gradient y\n")
+ tab_write("color_map {\n")
+ # XXX Does not exists anymore
+ # if render.alpha_mode == 'STRAIGHT':
+ # tab_write("[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.horizon_color[:]))
+ # tab_write("[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.zenith_color[:]))
+ if render.alpha_mode == 'TRANSPARENT':
+ tab_write("[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.pov.horizon_color[:]))
+ # aa premult not solved with transmit 1
+ tab_write("[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.pov.zenith_color[:]))
+ else:
+ tab_write("[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.pov.horizon_color[:]))
+ tab_write("[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.pov.zenith_color[:]))
+ tab_write("}\n")
+ tab_write("}\n")
+ tab_write("}\n")
+ # Sky_sphere alpha (transmit) is not translating into image alpha the same
+ # way as 'background'
+
+ # if world.pov.light_settings.use_indirect_light:
+ # scene.pov.radio_enable=1
+
+ # Maybe change the above to a function copyInternalRenderer settings when
+ # user pushes a button, then:
+ # scene.pov.radio_enable = world.pov.light_settings.use_indirect_light
+ # and other such translations but maybe this would not be allowed either?
+
+ ###############################################################
+
+ mist = world.mist_settings
+
+ if mist.use_mist:
+ tab_write("fog {\n")
+ if mist.falloff == 'LINEAR':
+ tab_write("distance %.6f\n" % ((mist.start + mist.depth) * 0.368))
+ elif mist.falloff == 'QUADRATIC': # n**2 or squrt(n)?
+ tab_write("distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368))
+ elif mist.falloff == 'INVERSE_QUADRATIC': # n**2 or squrt(n)?
+ tab_write("distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368))
+ tab_write(
+ "color rgbt<%.3g, %.3g, %.3g, %.3g>\n"
+ % (*world.pov.horizon_color, 1.0 - mist.intensity)
+ )
+ # tab_write("fog_offset %.6f\n" % mist.start) #create a pov property to prepend
+ # tab_write("fog_alt %.6f\n" % mist.height) #XXX right?
+ # tab_write("turbulence 0.2\n")
+ # tab_write("turb_depth 0.3\n")
+ tab_write("fog_type 1\n") # type2 for height
+ tab_write("}\n")
+ if scene.pov.media_enable:
+ tab_write("media {\n")
+ tab_write(
+ "scattering { %d, rgb %.12f*<%.4g, %.4g, %.4g>\n"
+ % (
+ int(scene.pov.media_scattering_type),
+ (scene.pov.media_diffusion_scale),
+ *(scene.pov.media_diffusion_color[:]),
+ )
+ )
+ if scene.pov.media_scattering_type == '5':
+ tab_write("eccentricity %.3g\n" % scene.pov.media_eccentricity)
+ tab_write("}\n")
+ tab_write(
+ "absorption %.12f*<%.4g, %.4g, %.4g>\n"
+ % (scene.pov.media_absorption_scale, *(scene.pov.media_absorption_color[:]))
+ )
+ tab_write("\n")
+ tab_write("samples %.d\n" % scene.pov.media_samples)
+ tab_write("}\n")
+
+
+####################################################################################################
+def export_rainbows(rainbows, file, scene, global_matrix, write_matrix, tab_write):
+ """write all POV rainbows primitives to exported file """
+ for ob in rainbows:
+ povdataname = ob.data.name # enough? XXX not used nor matrix fn?
+ angle = degrees(ob.data.spot_size / 2.5) # radians in blender (2
+ width = ob.data.spot_blend * 10
+ distance = ob.data.shadow_buffer_clip_start
+ # eps=0.0000001
+ # angle = br/(cr+eps) * 10 #eps is small epsilon variable to avoid dividing by zero
+ # width = ob.dimensions[2] #now let's say width of rainbow is the actual proxy height
+ # formerly:
+ # cz-bz # let's say width of the rainbow is height of the cone (interfacing choice
+
+ # v(A,B) rotates vector A about origin by vector B.
+ # and avoid a 0 length vector by adding 1
+
+ # file.write("#declare %s_Target= vrotate(<%.6g,%.6g,%.6g>,<%.4g,%.4g,%.4g>);\n" % \
+ # (povdataname, -(ob.location.x+0.1), -(ob.location.y+0.1), -(ob.location.z+0.1),
+ # ob.rotation_euler.x, ob.rotation_euler.y, ob.rotation_euler.z))
+
+ direction = ( # XXX currently not used (replaced by track to?)
+ ob.location.x,
+ ob.location.y,
+ ob.location.z,
+ ) # not taking matrix into account
+ rmatrix = global_matrix @ ob.matrix_world
+
+ # ob.rotation_euler.to_matrix().to_4x4() * mathutils.Vector((0,0,1))
+ # XXX Is result of the below offset by 90 degrees?
+ up = ob.matrix_world.to_3x3()[1].xyz # * global_matrix
+
+ # XXX TO CHANGE:
+ # formerly:
+ # tab_write("#declare %s = rainbow {\n"%povdataname)
+
+ # clumsy for now but remove the rainbow from instancing
+ # system because not an object. use lamps later instead of meshes
+
+ # del data_ref[dataname]
+ tab_write("rainbow {\n")
+
+ tab_write("angle %.4f\n" % angle)
+ tab_write("width %.4f\n" % width)
+ tab_write("distance %.4f\n" % distance)
+ tab_write("arc_angle %.4f\n" % ob.pov.arc_angle)
+ tab_write("falloff_angle %.4f\n" % ob.pov.falloff_angle)
+ tab_write("direction <%.4f,%.4f,%.4f>\n" % rmatrix.translation[:])
+ tab_write("up <%.4f,%.4f,%.4f>\n" % (up[0], up[1], up[2]))
+ tab_write("color_map {\n")
+ tab_write("[0.000 color srgbt<1.0, 0.5, 1.0, 1.0>]\n")
+ tab_write("[0.130 color srgbt<0.5, 0.5, 1.0, 0.9>]\n")
+ tab_write("[0.298 color srgbt<0.2, 0.2, 1.0, 0.7>]\n")
+ tab_write("[0.412 color srgbt<0.2, 1.0, 1.0, 0.4>]\n")
+ tab_write("[0.526 color srgbt<0.2, 1.0, 0.2, 0.4>]\n")
+ tab_write("[0.640 color srgbt<1.0, 1.0, 0.2, 0.4>]\n")
+ tab_write("[0.754 color srgbt<1.0, 0.5, 0.2, 0.6>]\n")
+ tab_write("[0.900 color srgbt<1.0, 0.2, 0.2, 0.7>]\n")
+ tab_write("[1.000 color srgbt<1.0, 0.2, 0.2, 1.0>]\n")
+ tab_write("}\n")
+
+ pov_mat_name = "Default_texture"
+ # tab_write("texture {%s}\n"%pov_mat_name)
+ write_object_modifiers(scene, ob, file)
+ # tab_write("rotate x*90\n")
+ # matrix = global_matrix @ ob.matrix_world
+ # write_matrix(matrix)
+ tab_write("}\n")
+ # continue #Don't render proxy mesh, skip to next object
+
+
+def export_smoke(file, smoke_obj_name, smoke_path, comments, global_matrix, write_matrix):
+ """export Blender smoke type fluids to pov media using df3 library"""
+
+ flowtype = -1 # XXX todo: not used yet? should trigger emissive for fire type
+ depsgraph = bpy.context.evaluated_depsgraph_get()
+ smoke_obj = bpy.data.objects[smoke_obj_name].evaluated_get(depsgraph)
+ domain = None
+ smoke_modifier = None
+ # Search smoke domain target for smoke modifiers
+ for mod in smoke_obj.modifiers:
+ if mod.type == 'FLUID':
+ if mod.fluid_type == 'FLOW':
+ if mod.flow_settings.flow_type == 'BOTH':
+ flowtype = 2
+ else:
+ if mod.flow_settings.smoke_flow_type == 'SMOKE':
+ flowtype = 0
+ else:
+ if mod.flow_settings.smoke_flow_type == 'FIRE':
+ flowtype = 1
+
+ if mod.fluid_type == 'DOMAIN':
+ domain = smoke_obj
+ smoke_modifier = mod
+
+ eps = 0.000001 # XXX not used currently. restore from corner case ... zero div?
+ if domain is not None:
+ mod_set = smoke_modifier.domain_settings
+ channeldata = []
+ for v in mod_set.density_grid:
+ channeldata.append(v.real)
+ print(v.real)
+ ## Usage en voxel texture:
+ # channeldata = []
+ # if channel == 'density':
+ # for v in mod_set.density_grid:
+ # channeldata.append(v.real)
+
+ # if channel == 'fire':
+ # for v in mod_set.flame_grid:
+ # channeldata.append(v.real)
+
+ resolution = mod_set.resolution_max
+ big_res = []
+ big_res.append(mod_set.domain_resolution[0])
+ big_res.append(mod_set.domain_resolution[1])
+ big_res.append(mod_set.domain_resolution[2])
+
+ if mod_set.use_noise:
+ big_res[0] = big_res[0] * (mod_set.noise_scale + 1)
+ big_res[1] = big_res[1] * (mod_set.noise_scale + 1)
+ big_res[2] = big_res[2] * (mod_set.noise_scale + 1)
+ # else:
+ # p = []
+ ##gather smoke domain settings
+ # BBox = domain.bound_box
+ # p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
+ # p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
+ # mod_set = smoke_modifier.domain_settings
+ # resolution = mod_set.resolution_max
+ # smokecache = mod_set.point_cache
+ # ret = read_cache(smokecache, mod_set.use_noise, mod_set.noise_scale + 1, flowtype)
+ # res_x = ret[0]
+ # res_y = ret[1]
+ # res_z = ret[2]
+ # density = ret[3]
+ # fire = ret[4]
+
+ # if res_x * res_y * res_z > 0:
+ ##new cache format
+ # big_res = []
+ # big_res.append(res_x)
+ # big_res.append(res_y)
+ # big_res.append(res_z)
+ # else:
+ # max = domain.dimensions[0]
+ # if (max - domain.dimensions[1]) < -eps:
+ # max = domain.dimensions[1]
+
+ # if (max - domain.dimensions[2]) < -eps:
+ # max = domain.dimensions[2]
+
+ # big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
+ # int(round(resolution * domain.dimensions[1] / max, 0)),
+ # int(round(resolution * domain.dimensions[2] / max, 0))]
+
+ # if mod_set.use_noise:
+ # big_res = [big_res[0] * (mod_set.noise_scale + 1),
+ # big_res[1] * (mod_set.noise_scale + 1),
+ # big_res[2] * (mod_set.noise_scale + 1)]
+
+ # if channel == 'density':
+ # channeldata = density
+
+ # if channel == 'fire':
+ # channeldata = fire
+
+ # sc_fr = '%s/%s/%s/%05d' % (
+ # efutil.export_path,
+ # efutil.scene_filename(),
+ # bpy.context.scene.name,
+ # bpy.context.scene.frame_current
+ # )
+ # if not os.path.exists( sc_fr ):
+ # os.makedirs(sc_fr)
+ #
+ # smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
+ # smoke_path = '/'.join([sc_fr, smoke_filename])
+ #
+ # with open(smoke_path, 'wb') as smoke_file:
+ # # Binary densitygrid file format
+ # #
+ # # File header
+ # smoke_file.write(b'SMOKE') #magic number
+ # smoke_file.write(struct.pack('<I', big_res[0]))
+ # smoke_file.write(struct.pack('<I', big_res[1]))
+ # smoke_file.write(struct.pack('<I', big_res[2]))
+ # Density data
+ # smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
+ #
+ # LuxLog('Binary SMOKE file written: %s' % (smoke_path))
+
+ # return big_res[0], big_res[1], big_res[2], channeldata
+
+ mydf3 = df3_library.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(smoke_path)
+ 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(" } // end scattering\n")
+ file.write(" density{density_file df3 \"%s\"\n" % (smoke_path))
+ 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...
+ write_matrix(global_matrix @ smoke_obj.matrix_world)
+
+ # END OF TRANSFORMATIONS
+
+ file.write("}\n")
+
+ # file.write(" interpolate 1\n")
+ # file.write(" frequency 0\n")
+ # file.write(" }\n")
+ # file.write("}\n")
+
+
+classes = ()
+
+
+def register():
+ for cls in classes:
+ register_class(cls)
+
+
+def unregister():
+ for cls in classes:
+ unregister_class(cls)
diff --git a/render_povray/scenography_gui.py b/render_povray/scenography_gui.py
new file mode 100755
index 00000000..6eb5aed9
--- /dev/null
+++ b/render_povray/scenography_gui.py
@@ -0,0 +1,761 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""User interface to camera frame, optics distortions, and environment
+
+with world, sky, atmospheric effects such as rainbows or smoke """
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import Operator, Menu, Panel
+from bl_operators.presets import AddPresetBase
+
+from bl_ui import properties_data_camera
+
+for member in dir(properties_data_camera):
+ subclass = getattr(properties_data_camera, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_data_camera
+
+# ##################################
+# # Use only a subset of the world panels
+# from bl_ui import properties_world
+
+# # TORECREATE##DEPRECATED#properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER')
+# properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER')
+# # TORECREATE##DEPRECATED#properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER')
+# del properties_world
+
+##################################
+# Physics Main wrapping every class 'as is'
+from bl_ui import properties_physics_common
+
+for member in dir(properties_physics_common):
+ subclass = getattr(properties_physics_common, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_physics_common
+
+# Physics Rigid Bodies wrapping every class 'as is'
+from bl_ui import properties_physics_rigidbody
+
+for member in dir(properties_physics_rigidbody):
+ subclass = getattr(properties_physics_rigidbody, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_physics_rigidbody
+
+# Physics Rigid Body Constraint wrapping every class 'as is'
+from bl_ui import properties_physics_rigidbody_constraint
+
+for member in dir(properties_physics_rigidbody_constraint):
+ subclass = getattr(properties_physics_rigidbody_constraint, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_physics_rigidbody_constraint
+
+# Physics Smoke and fluids wrapping every class 'as is'
+from bl_ui import properties_physics_fluid
+
+for member in dir(properties_physics_fluid):
+ subclass = getattr(properties_physics_fluid, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_physics_fluid
+
+# Physics softbody wrapping every class 'as is'
+from bl_ui import properties_physics_softbody
+
+for member in dir(properties_physics_softbody):
+ subclass = getattr(properties_physics_softbody, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_physics_softbody
+
+# Physics Field wrapping every class 'as is'
+from bl_ui import properties_physics_field
+
+for member in dir(properties_physics_field):
+ subclass = getattr(properties_physics_field, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_physics_field
+
+# Physics Cloth wrapping every class 'as is'
+from bl_ui import properties_physics_cloth
+
+for member in dir(properties_physics_cloth):
+ subclass = getattr(properties_physics_cloth, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_physics_cloth
+
+# Physics Dynamic Paint wrapping every class 'as is'
+from bl_ui import properties_physics_dynamicpaint
+
+for member in dir(properties_physics_dynamicpaint):
+ subclass = getattr(properties_physics_dynamicpaint, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_physics_dynamicpaint
+
+from bl_ui import properties_particle
+
+for member in dir(properties_particle): # add all "particle" panels from blender
+ subclass = getattr(properties_particle, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_particle
+
+
+class CameraDataButtonsPanel:
+ """Use this class to define buttons from the camera data tab of
+ properties window."""
+
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ cam = context.camera
+ rd = context.scene.render
+ return cam and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class WorldButtonsPanel:
+ """Use this class to define buttons from the world tab of
+ properties window."""
+
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "world"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ wld = context.world
+ rd = context.scene.render
+ return wld and (rd.engine in cls.COMPAT_ENGINES)
+
+
+###############################################################################
+# Camera Settings
+###############################################################################
+class CAMERA_PT_POV_cam_dof(CameraDataButtonsPanel, Panel):
+ """Use this class for camera depth of field focal blur buttons."""
+
+ bl_label = "POV Aperture"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ bl_parent_id = "DATA_PT_camera_dof_aperture"
+ bl_options = {'HIDE_HEADER'}
+ # def draw_header(self, context):
+ # cam = context.camera
+
+ # self.layout.prop(cam.pov, "dof_enable", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ cam = context.camera
+
+ layout.active = cam.dof.use_dof
+ layout.use_property_split = True # Active single-column layout
+
+ flow = layout.grid_flow(
+ row_major=True, columns=0, even_columns=True, even_rows=False, align=False
+ )
+
+ col = flow.column()
+ col.label(text="F-Stop value will export as")
+ col.label(text="POV aperture : " + "%.3f" % (1 / cam.dof.aperture_fstop * 1000))
+
+ col = flow.column()
+ col.prop(cam.pov, "dof_samples_min")
+ col.prop(cam.pov, "dof_samples_max")
+ col.prop(cam.pov, "dof_variance")
+ col.prop(cam.pov, "dof_confidence")
+
+
+class CAMERA_PT_POV_cam_nor(CameraDataButtonsPanel, Panel):
+ """Use this class for camera normal perturbation buttons."""
+
+ bl_label = "POV Perturbation"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw_header(self, context):
+ cam = context.camera
+
+ self.layout.prop(cam.pov, "normal_enable", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ cam = context.camera
+
+ layout.active = cam.pov.normal_enable
+
+ layout.prop(cam.pov, "normal_patterns")
+ layout.prop(cam.pov, "cam_normal")
+ layout.prop(cam.pov, "turbulence")
+ layout.prop(cam.pov, "scale")
+
+
+class CAMERA_PT_POV_replacement_text(CameraDataButtonsPanel, Panel):
+ """Use this class for camera text replacement field."""
+
+ bl_label = "Custom POV Code"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ cam = context.camera
+
+ col = layout.column()
+ col.label(text="Replace properties with:")
+ col.prop(cam.pov, "replacement_text", text="")
+
+
+###############################################################################
+# World background and sky sphere Settings
+###############################################################################
+
+
+class WORLD_PT_POV_world(WorldButtonsPanel, Panel):
+ """Use this class to define pov world buttons"""
+
+ bl_label = "World"
+
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ world = context.world.pov
+
+ row = layout.row(align=True)
+ row.menu(WORLD_MT_POV_presets.__name__, text=WORLD_MT_POV_presets.bl_label)
+ row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='ADD')
+ row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='REMOVE').remove_active = True
+
+ row = layout.row()
+ row.prop(world, "use_sky_paper")
+ row.prop(world, "use_sky_blend")
+ row.prop(world, "use_sky_real")
+
+ row = layout.row()
+ row.column().prop(world, "horizon_color")
+ col = row.column()
+ col.prop(world, "zenith_color")
+ col.active = world.use_sky_blend
+ row.column().prop(world, "ambient_color")
+
+ # row = layout.row()
+ # row.prop(world, "exposure") #Re-implement later as a light multiplier
+ # row.prop(world, "color_range")
+
+
+class WORLD_PT_POV_mist(WorldButtonsPanel, Panel):
+ """Use this class to define pov mist buttons."""
+
+ bl_label = "Mist"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw_header(self, context):
+ world = context.world
+
+ self.layout.prop(world.mist_settings, "use_mist", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ world = context.world
+
+ layout.active = world.mist_settings.use_mist
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(world.mist_settings, "intensity")
+ col.prop(world.mist_settings, "start")
+
+ col = split.column()
+ col.prop(world.mist_settings, "depth")
+ col.prop(world.mist_settings, "height")
+
+ layout.prop(world.mist_settings, "falloff")
+
+
+class WORLD_MT_POV_presets(Menu):
+ """Apply world preset to all concerned properties"""
+
+ bl_label = "World Presets"
+ preset_subdir = "pov/world"
+ preset_operator = "script.execute_preset"
+ draw = bpy.types.Menu.draw_preset
+
+
+class WORLD_OT_POV_add_preset(AddPresetBase, Operator):
+ """Add a World Preset recording current values"""
+
+ bl_idname = "object.world_preset_add"
+ bl_label = "Add World Preset"
+ preset_menu = "WORLD_MT_POV_presets"
+
+ # variable used for all preset values
+ preset_defines = ["scene = bpy.context.scene"]
+
+ # properties to store in the preset
+ preset_values = [
+ "scene.world.use_sky_blend",
+ "scene.world.horizon_color",
+ "scene.world.zenith_color",
+ "scene.world.ambient_color",
+ "scene.world.mist_settings.use_mist",
+ "scene.world.mist_settings.intensity",
+ "scene.world.mist_settings.depth",
+ "scene.world.mist_settings.start",
+ "scene.pov.media_enable",
+ "scene.pov.media_scattering_type",
+ "scene.pov.media_samples",
+ "scene.pov.media_diffusion_scale",
+ "scene.pov.media_diffusion_color",
+ "scene.pov.media_absorption_scale",
+ "scene.pov.media_absorption_color",
+ "scene.pov.media_eccentricity",
+ ]
+
+ # where to store the preset
+ preset_subdir = "pov/world"
+
+
+class RENDER_PT_POV_media(WorldButtonsPanel, Panel):
+ """Use this class to define a pov global atmospheric media buttons."""
+
+ bl_label = "Atmosphere Media"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw_header(self, context):
+ scene = context.scene
+
+ self.layout.prop(scene.pov, "media_enable", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+
+ layout.active = scene.pov.media_enable
+
+ col = layout.column()
+ col.prop(scene.pov, "media_scattering_type", text="")
+ col = layout.column()
+ col.prop(scene.pov, "media_samples", text="Samples")
+ split = layout.split()
+ col = split.column(align=True)
+ col.label(text="Scattering:")
+ col.prop(scene.pov, "media_diffusion_scale")
+ col.prop(scene.pov, "media_diffusion_color", text="")
+ col = split.column(align=True)
+ col.label(text="Absorption:")
+ col.prop(scene.pov, "media_absorption_scale")
+ col.prop(scene.pov, "media_absorption_color", text="")
+ if scene.pov.media_scattering_type == '5':
+ col = layout.column()
+ col.prop(scene.pov, "media_eccentricity", text="Eccentricity")
+
+
+###############################################################################
+# Lights settings
+###############################################################################
+
+################################################################################
+# from bl_ui import properties_data_light
+# for member in dir(properties_data_light):
+# subclass = getattr(properties_data_light, member)
+# try:
+# subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+# except BaseException as e:
+# print e.__doc__
+# print('An exception occurred: {}'.format(e))
+# pass
+# del properties_data_light
+#########################LIGHTS################################
+
+from bl_ui import properties_data_light
+
+# # These panels are kept
+# properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add('POVRAY_RENDER')
+# properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER')
+
+## make some native panels contextual to some object variable
+## by recreating custom panels inheriting their properties
+class PovLightButtonsPanel(properties_data_light.DataButtonsPanel):
+ """Use this class to define buttons from the light data tab of
+ properties window."""
+
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ POV_OBJECT_TYPES = {'RAINBOW'}
+
+ @classmethod
+ def poll(cls, context):
+ obj = context.object
+ # We use our parent class poll func too, avoids to re-define too much things...
+ return (
+ super(PovLightButtonsPanel, cls).poll(context)
+ and obj
+ and obj.pov.object_as not in cls.POV_OBJECT_TYPES
+ )
+
+
+# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
+# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
+# So we simply have to explicitly copy here the interesting bits. ;)
+from bl_ui import properties_data_light
+
+# for member in dir(properties_data_light):
+# subclass = getattr(properties_data_light, member)
+# try:
+# subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+# except BaseException as e:
+# print(e.__doc__)
+# print('An exception occurred: {}'.format(e))
+# pass
+
+# Now only These panels are kept
+properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add('POVRAY_RENDER')
+properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER')
+
+
+class LIGHT_PT_POV_preview(PovLightButtonsPanel, Panel):
+ # XXX Needs update and docstring
+ bl_label = properties_data_light.DATA_PT_preview.bl_label
+
+ draw = properties_data_light.DATA_PT_preview.draw
+
+
+class LIGHT_PT_POV_light(PovLightButtonsPanel, Panel):
+ """UI panel to main pov light parameters"""
+
+ # bl_label = properties_data_light.DATA_PT_light.bl_label
+
+ # draw = properties_data_light.DATA_PT_light.draw
+ # class DATA_PT_POV_light(DataButtonsPanel, Panel):
+ bl_label = "Light"
+ # COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ light = context.light
+
+ layout.row().prop(light, "type", expand=True)
+
+ split = layout.split()
+
+ col = split.column()
+ sub = col.column()
+ sub.prop(light, "color", text="")
+ sub.prop(light, "energy")
+
+ if light.type in {'POINT', 'SPOT'}:
+ sub.label(text="Falloff:")
+ sub.prop(light, "falloff_type", text="")
+ sub.prop(light, "distance")
+
+ if light.falloff_type == 'LINEAR_QUADRATIC_WEIGHTED':
+ col.label(text="Attenuation Factors:")
+ sub = col.column(align=True)
+ sub.prop(light, "linear_attenuation", slider=True, text="Linear")
+ sub.prop(light, "quadratic_attenuation", slider=True, text="Quadratic")
+
+ elif light.falloff_type == 'INVERSE_COEFFICIENTS':
+ col.label(text="Inverse Coefficients:")
+ sub = col.column(align=True)
+ sub.prop(light, "constant_coefficient", text="Constant")
+ sub.prop(light, "linear_coefficient", text="Linear")
+ sub.prop(light, "quadratic_coefficient", text="Quadratic")
+
+ if light.type == 'AREA':
+ col.prop(light, "distance")
+
+ # restore later as interface to POV light groups ?
+ # col = split.column()
+ # col.prop(light, "use_own_layer", text="This Layer Only")
+
+
+class LIGHT_MT_POV_presets(Menu):
+ """Use this class to define preset menu for pov lights."""
+
+ bl_label = "Lamp Presets"
+ preset_subdir = "pov/light"
+ preset_operator = "script.execute_preset"
+ draw = bpy.types.Menu.draw_preset
+
+
+class LIGHT_OT_POV_add_preset(AddPresetBase, Operator):
+ """Operator to add a Light Preset"""
+
+ bl_idname = "object.light_preset_add"
+ bl_label = "Add Light Preset"
+ preset_menu = "LIGHT_MT_POV_presets"
+
+ # variable used for all preset values
+ preset_defines = ["lightdata = bpy.context.object.data"]
+
+ # properties to store in the preset
+ preset_values = ["lightdata.type", "lightdata.color"]
+
+ # where to store the preset
+ preset_subdir = "pov/light"
+
+
+# Draw into the existing light panel
+def light_panel_func(self, context):
+ """Menu to browse and add light preset"""
+ layout = self.layout
+
+ row = layout.row(align=True)
+ row.menu(LIGHT_MT_POV_presets.__name__, text=LIGHT_MT_POV_presets.bl_label)
+ row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='ADD')
+ row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='REMOVE').remove_active = True
+
+
+'''#TORECREATE##DEPRECATED#
+class LIGHT_PT_POV_sunsky(PovLightButtonsPanel, Panel):
+ bl_label = properties_data_light.DATA_PT_sunsky.bl_label
+
+ @classmethod
+ def poll(cls, context):
+ lamp = context.light
+ engine = context.scene.render.engine
+ return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES)
+
+ draw = properties_data_light.DATA_PT_sunsky.draw
+
+'''
+
+
+class LIGHT_PT_POV_shadow(PovLightButtonsPanel, Panel):
+ # Todo : update and docstring
+ bl_label = "Shadow"
+
+ @classmethod
+ def poll(cls, context):
+ light = context.light
+ engine = context.scene.render.engine
+ return light and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ light = context.light
+
+ layout.row().prop(light.pov, "shadow_method", expand=True)
+
+ split = layout.split()
+ col = split.column()
+
+ col.prop(light.pov, "use_halo")
+ sub = col.column(align=True)
+ sub.active = light.pov.use_halo
+ sub.prop(light.pov, "halo_intensity", text="Intensity")
+
+ if light.pov.shadow_method == 'NOSHADOW' and light.type == 'AREA':
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Form factor sampling:")
+
+ sub = col.row(align=True)
+
+ if light.shape == 'SQUARE':
+ sub.prop(light, "shadow_ray_samples_x", text="Samples")
+ elif light.shape == 'RECTANGLE':
+ sub.prop(light.pov, "shadow_ray_samples_x", text="Samples X")
+ sub.prop(light.pov, "shadow_ray_samples_y", text="Samples Y")
+
+ if light.pov.shadow_method != 'NOSHADOW':
+ split = layout.split()
+
+ col = split.column()
+ col.prop(light, "shadow_color", text="")
+
+ # col = split.column()
+ # col.prop(light.pov, "use_shadow_layer", text="This Layer Only")
+ # col.prop(light.pov, "use_only_shadow")
+
+ if light.pov.shadow_method == 'RAY_SHADOW':
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Sampling:")
+
+ if light.type in {'POINT', 'SUN', 'SPOT'}:
+ sub = col.row()
+
+ sub.prop(light.pov, "shadow_ray_samples_x", text="Samples")
+ # any equivalent in pov?
+ # sub.prop(light, "shadow_soft_size", text="Soft Size")
+
+ elif light.type == 'AREA':
+ sub = col.row(align=True)
+
+ if light.shape == 'SQUARE':
+ sub.prop(light.pov, "shadow_ray_samples_x", text="Samples")
+ elif light.shape == 'RECTANGLE':
+ sub.prop(light.pov, "shadow_ray_samples_x", text="Samples X")
+ sub.prop(light.pov, "shadow_ray_samples_y", text="Samples Y")
+
+
+class LIGHT_PT_POV_area(PovLightButtonsPanel, Panel):
+ """Area light UI panel"""
+
+ bl_label = properties_data_light.DATA_PT_area.bl_label
+ bl_parent_id = "LIGHT_PT_POV_light"
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ lamp = context.light
+ engine = context.scene.render.engine
+ return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES)
+
+ draw = properties_data_light.DATA_PT_area.draw
+
+
+class LIGHT_PT_POV_spot(PovLightButtonsPanel, Panel):
+ bl_label = properties_data_light.DATA_PT_spot.bl_label
+ bl_parent_id = "LIGHT_PT_POV_light"
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ lamp = context.light
+ engine = context.scene.render.engine
+ return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
+
+ draw = properties_data_light.DATA_PT_spot.draw
+
+
+class LIGHT_PT_POV_falloff_curve(PovLightButtonsPanel, Panel):
+ bl_label = properties_data_light.DATA_PT_falloff_curve.bl_label
+ bl_options = properties_data_light.DATA_PT_falloff_curve.bl_options
+
+ @classmethod
+ def poll(cls, context):
+ lamp = context.light
+ engine = context.scene.render.engine
+
+ return (
+ lamp and lamp.type in {'POINT', 'SPOT'} and lamp.falloff_type == 'CUSTOM_CURVE'
+ ) and (engine in cls.COMPAT_ENGINES)
+
+ draw = properties_data_light.DATA_PT_falloff_curve.draw
+
+
+class OBJECT_PT_POV_rainbow(PovLightButtonsPanel, Panel):
+ """Use this class to define buttons from the rainbow panel of
+ properties window. inheriting lamp buttons panel class"""
+
+ bl_label = "POV-Ray Rainbow"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ # bl_options = {'HIDE_HEADER'}
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ obj = context.object
+ return obj and obj.pov.object_as == 'RAINBOW' and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ obj = context.object
+
+ col = layout.column()
+
+ if obj.pov.object_as == 'RAINBOW':
+ if not obj.pov.unlock_parameters:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
+ )
+ col.label(text="Rainbow projection angle: " + str(obj.data.spot_size))
+ col.label(text="Rainbow width: " + str(obj.data.spot_blend))
+ col.label(text="Rainbow distance: " + str(obj.data.shadow_buffer_clip_start))
+ col.label(text="Rainbow arc angle: " + str(obj.pov.arc_angle))
+ col.label(text="Rainbow falloff angle: " + str(obj.pov.falloff_angle))
+
+ else:
+ col.prop(
+ obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
+ )
+ col.label(text="3D view proxy may get out of synch")
+ col.active = obj.pov.unlock_parameters
+
+ layout.operator("pov.cone_update", text="Update", icon="MESH_CONE")
+
+ # col.label(text="Parameters:")
+ col.prop(obj.data, "spot_size", text="Rainbow Projection Angle")
+ col.prop(obj.data, "spot_blend", text="Rainbow width")
+ col.prop(obj.data, "shadow_buffer_clip_start", text="Visibility distance")
+ col.prop(obj.pov, "arc_angle")
+ col.prop(obj.pov, "falloff_angle")
+
+
+del properties_data_light
+
+
+classes = (
+ WORLD_PT_POV_world,
+ WORLD_MT_POV_presets,
+ WORLD_OT_POV_add_preset,
+ WORLD_PT_POV_mist,
+ RENDER_PT_POV_media,
+ LIGHT_PT_POV_preview,
+ LIGHT_PT_POV_light,
+ LIGHT_PT_POV_shadow,
+ LIGHT_PT_POV_spot,
+ LIGHT_PT_POV_area,
+ LIGHT_MT_POV_presets,
+ LIGHT_OT_POV_add_preset,
+ OBJECT_PT_POV_rainbow,
+ CAMERA_PT_POV_cam_dof,
+ CAMERA_PT_POV_cam_nor,
+ CAMERA_PT_POV_replacement_text,
+)
+
+
+def register():
+
+ for cls in classes:
+ register_class(cls)
+ bpy.types.LIGHT_PT_POV_light.prepend(light_panel_func)
+
+
+def unregister():
+
+ bpy.types.LIGHT_PT_POV_light.remove(light_panel_func)
+ for cls in reversed(classes):
+ unregister_class(cls)
+
diff --git a/render_povray/scenography_properties.py b/render_povray/scenography_properties.py
new file mode 100755
index 00000000..dd886513
--- /dev/null
+++ b/render_povray/scenography_properties.py
@@ -0,0 +1,392 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare stage set and surrounding (camera, lights, environment) properties controllable in UI"""
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+ FloatVectorProperty,
+ StringProperty,
+ BoolProperty,
+ IntProperty,
+ FloatProperty,
+ EnumProperty,
+ PointerProperty,
+ CollectionProperty,
+)
+
+from .shading_properties import (
+ active_texture_name_from_uilist,
+ active_texture_name_from_search,
+ brush_texture_update,
+)
+
+###############################################################################
+# Camera POV properties.
+###############################################################################
+class RenderPovSettingsCamera(PropertyGroup):
+
+ """Declare camera properties controllable in UI and translated to POV."""
+
+ # DOF Toggle
+ dof_enable: BoolProperty(
+ name="Depth Of Field", description="Enable POV Depth Of Field ", default=False
+ )
+
+ # Aperture (Intensity of the Blur)
+ dof_aperture: FloatProperty(
+ name="Aperture",
+ description="Similar to a real camera's aperture effect over focal blur (though not "
+ "in physical units and independent of focal length). "
+ "Increase to get more blur",
+ min=0.01,
+ max=1.00,
+ default=0.50,
+ )
+
+ # Aperture adaptive sampling
+ dof_samples_min: IntProperty(
+ name="Samples Min",
+ description="Minimum number of rays to use for each pixel",
+ min=1,
+ max=128,
+ default=3,
+ )
+
+ dof_samples_max: IntProperty(
+ name="Samples Max",
+ description="Maximum number of rays to use for each pixel",
+ min=1,
+ max=128,
+ default=9,
+ )
+
+ dof_variance: IntProperty(
+ name="Variance",
+ description="Minimum threshold (fractional value) for adaptive DOF sampling (up "
+ "increases quality and render time). The value for the variance should "
+ "be in the range of the smallest displayable color difference",
+ min=1,
+ max=100000,
+ soft_max=10000,
+ default=8192,
+ )
+
+ dof_confidence: FloatProperty(
+ name="Confidence",
+ description="Probability to reach the real color value. Larger confidence values "
+ "will lead to more samples, slower traces and better images",
+ min=0.01,
+ max=0.99,
+ default=0.20,
+ )
+
+ normal_enable: BoolProperty(name="Perturbated Camera", default=False)
+
+ cam_normal: FloatProperty(name="Normal Strength", min=0.0, max=1.0, default=0.001)
+
+ normal_patterns: EnumProperty(
+ name="Pattern",
+ description="",
+ items=(
+ ("agate", "Agate", ""),
+ ("boxed", "Boxed", ""),
+ ("bumps", "Bumps", ""),
+ ("cells", "Cells", ""),
+ ("crackle", "Crackle", ""),
+ ("dents", "Dents", ""),
+ ("granite", "Granite", ""),
+ ("leopard", "Leopard", ""),
+ ("marble", "Marble", ""),
+ ("onion", "Onion", ""),
+ ("pavement", "Pavement", ""),
+ ("planar", "Planar", ""),
+ ("quilted", "Quilted", ""),
+ ("ripples", "Ripples", ""),
+ ("radial", "Radial", ""),
+ ("spherical", "Spherical", ""),
+ ("spiral1", "Spiral1", ""),
+ ("spiral2", "Spiral2", ""),
+ ("spotted", "Spotted", ""),
+ ("square", "Square", ""),
+ ("tiling", "Tiling", ""),
+ ("waves", "Waves", ""),
+ ("wood", "Wood", ""),
+ ("wrinkles", "Wrinkles", ""),
+ ),
+ default="agate",
+ )
+
+ turbulence: FloatProperty(name="Turbulence", min=0.0, max=100.0, default=0.1)
+
+ scale: FloatProperty(name="Scale", min=0.0, default=1.0)
+
+ ##################################CustomPOV Code############################
+ # Only DUMMIES below for now:
+ replacement_text: StringProperty(
+ name="Texts in blend file",
+ description="Type the declared name in custom POV code or an external .inc "
+ "it points at. camera {} expected",
+ default="",
+ )
+
+
+###############################################################################
+# Light POV properties.
+###############################################################################
+class RenderPovSettingsLight(PropertyGroup):
+
+ """Declare light properties controllable in UI and translated to POV."""
+
+ # former Space properties from removed Blender Internal
+ use_limited_texture_context: BoolProperty(
+ name="",
+ description="Use the limited version of texture user (for ‘old shading’ mode)",
+ default=True,
+ )
+
+ texture_context: EnumProperty(
+ name="Texture context",
+ description="Type of texture data to display and edit",
+ items=(
+ ("MATERIAL", "", "Show material textures", "MATERIAL", 0), # "Show material textures"
+ ("WORLD", "", "Show world textures", "WORLD", 1), # "Show world textures"
+ ("LAMP", "", "Show lamp textures", "LIGHT", 2), # "Show lamp textures"
+ (
+ "PARTICLES",
+ "",
+ "Show particles textures",
+ "PARTICLES",
+ 3,
+ ), # "Show particles textures"
+ (
+ "LINESTYLE",
+ "",
+ "Show linestyle textures",
+ "LINE_DATA",
+ 4,
+ ), # "Show linestyle textures"
+ (
+ "OTHER",
+ "",
+ "Show other data textures",
+ "TEXTURE_DATA",
+ 5,
+ ), # "Show other data textures"
+ ),
+ default="MATERIAL",
+ )
+
+ shadow_method: EnumProperty(
+ name="Shadow",
+ description="",
+ items=(
+ ("NOSHADOW", "No Shadow", "No Shadow"),
+ ("RAY_SHADOW", "Ray Shadow", "Ray Shadow, Use ray tracing for shadow"),
+ ),
+ default="RAY_SHADOW",
+ )
+
+ active_texture_index: IntProperty(name="Index for texture_slots", default=0)
+
+ use_halo: BoolProperty(
+ name="Halo", description="Render spotlight with a volumetric halo", default=False
+ )
+
+ halo_intensity: FloatProperty(
+ name="Halo intensity",
+ description="Brightness of the spotlight halo cone",
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+ shadow_ray_samples_x: IntProperty(
+ name="Number of samples taken extra (samples x samples)", min=1, soft_max=64, default=1
+ )
+
+ shadow_ray_samples_y: IntProperty(
+ name="Number of samples taken extra (samples x samples)", min=1, soft_max=64, default=1
+ )
+
+ shadow_ray_sample_method: EnumProperty(
+ name="",
+ description="Method for generating shadow samples: Adaptive QMC is fastest,"
+ "Constant QMC is less noisy but slower",
+ items=(
+ ("ADAPTIVE_QMC", "", "Halton samples distribution", "", 0),
+ ("CONSTANT_QMC", "", "QMC samples distribution", "", 1),
+ (
+ "CONSTANT_JITTERED",
+ "",
+ "Uses POV jitter keyword",
+ "",
+ 2,
+ ), # "Show other data textures"
+ ),
+ default="CONSTANT_JITTERED",
+ )
+
+ use_jitter: BoolProperty(
+ name="Jitter",
+ description="Use noise for sampling (Constant Jittered sampling)",
+ default=False,
+ )
+
+
+###############################################################################
+# World POV properties.
+###############################################################################
+class RenderPovSettingsWorld(PropertyGroup):
+
+ """Declare world properties controllable in UI and translated to POV."""
+
+ # former Space properties from removed Blender Internal
+ use_limited_texture_context: BoolProperty(
+ name="",
+ description="Use the limited version of texture user (for ‘old shading’ mode)",
+ default=True,
+ )
+
+ texture_context: EnumProperty(
+ name="Texture context",
+ description="Type of texture data to display and edit",
+ items=(
+ ("MATERIAL", "", "Show material textures", "MATERIAL", 0), # "Show material textures"
+ ("WORLD", "", "Show world textures", "WORLD", 1), # "Show world textures"
+ ("LIGHT", "", "Show lamp textures", "LIGHT", 2), # "Show lamp textures"
+ (
+ "PARTICLES",
+ "",
+ "Show particles textures",
+ "PARTICLES",
+ 3,
+ ), # "Show particles textures"
+ (
+ "LINESTYLE",
+ "",
+ "Show linestyle textures",
+ "LINE_DATA",
+ 4,
+ ), # "Show linestyle textures"
+ (
+ "OTHER",
+ "",
+ "Show other data textures",
+ "TEXTURE_DATA",
+ 5,
+ ), # "Show other data textures"
+ ),
+ default="MATERIAL",
+ )
+
+ use_sky_blend: BoolProperty(
+ name="Blend Sky",
+ description="Render background with natural progression from horizon to zenith",
+ default=False,
+ )
+
+ use_sky_paper: BoolProperty(
+ name="Paper Sky", description="Flatten blend or texture coordinates", default=False
+ )
+
+ use_sky_real: BoolProperty(
+ name="Real Sky",
+ description="Render background with a real horizon, relative to the camera angle",
+ default=False,
+ )
+
+ horizon_color: FloatVectorProperty(
+ name="Horizon Color",
+ description="Color at the horizon",
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(0.050876, 0.050876, 0.050876),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ zenith_color: FloatVectorProperty(
+ name="Zenith Color",
+ description="Color at the zenith",
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(0.0, 0.0, 0.0),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ ambient_color: FloatVectorProperty(
+ name="Ambient Color",
+ description="Ambient color of the world",
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(0.0, 0.0, 0.0),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+ active_texture_index: IntProperty(
+ name="Index for texture_slots", default=0, update=brush_texture_update
+ )
+
+
+"""
+# class WORLD_TEXTURE_SLOTS_UL_layerlist(bpy.types.UIList):
+# texture_slots:
+
+class WorldTextureSlots(bpy.props.PropertyGroup):
+ index = bpy.prop.PropertyInt(name='index')
+ # foo = random prop
+
+bpy.types.World.texture_slots = bpy.props.CollectionProperty(type=PropertyGroup)
+
+for i in range(18): # length of world texture slots
+ world.texture_slots.add()
+"""
+
+classes = (
+ RenderPovSettingsCamera,
+ RenderPovSettingsLight,
+ RenderPovSettingsWorld,
+)
+
+
+def register():
+ for cls in classes:
+ register_class(cls)
+
+ bpy.types.Camera.pov = PointerProperty(type=RenderPovSettingsCamera)
+ bpy.types.Light.pov = PointerProperty(type=RenderPovSettingsLight)
+ bpy.types.World.pov = PointerProperty(type=RenderPovSettingsWorld)
+
+
+def unregister():
+ del bpy.types.Camera.pov
+ del bpy.types.Light.pov
+ del bpy.types.World.pov
+
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/scripting.py b/render_povray/scripting.py
new file mode 100755
index 00000000..02ca6444
--- /dev/null
+++ b/render_povray/scripting.py
@@ -0,0 +1,529 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""Support POV Scene Description Language snippets or full includes: import,
+
+load, create or edit"""
+
+import bpy
+from bpy.props import StringProperty, BoolProperty, CollectionProperty
+from bpy_extras.io_utils import ImportHelper
+
+from mathutils import Vector
+from math import pi
+
+
+def export_custom_code(file):
+ """write all POV user defined custom code to exported file """
+ # Write CurrentAnimation Frame for use in Custom POV Code
+ file.write("#declare CURFRAMENUM = %d;\n" % bpy.context.scene.frame_current)
+ # Change path and uncomment to add an animated include file by hand:
+ file.write("//#include \"/home/user/directory/animation_include_file.inc\"\n")
+ for txt in bpy.data.texts:
+ if txt.pov.custom_code == 'both':
+ # Why are the newlines needed?
+ file.write("\n")
+ file.write(txt.as_string())
+ file.write("\n")
+
+
+#############################IMPORT
+
+
+class ImportPOV(bpy.types.Operator, ImportHelper):
+ """Load Povray files"""
+
+ bl_idname = "import_scene.pov"
+ bl_label = "POV-Ray files (.pov/.inc)"
+ bl_options = {'PRESET', 'UNDO'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ # -----------
+ # File props.
+ files: CollectionProperty(
+ type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'}
+ )
+ directory: StringProperty(maxlen=1024, subtype='FILE_PATH', options={'HIDDEN', 'SKIP_SAVE'})
+
+ filename_ext = {".pov", ".inc"}
+ filter_glob: StringProperty(default="*.pov;*.inc", options={'HIDDEN'})
+
+ import_at_cur: BoolProperty(
+ name="Import at Cursor Location", description="Ignore Object Matrix", default=False
+ )
+
+ def execute(self, context):
+ from mathutils import Matrix
+
+ verts = []
+ faces = []
+ materials = []
+ blend_mats = [] ##############
+ pov_mats = [] ##############
+ colors = []
+ mat_names = []
+ lenverts = None
+ lenfaces = None
+ suffix = -1
+ name = 'Mesh2_%s' % suffix
+ name_search = False
+ verts_search = False
+ faces_search = False
+ plane_search = False
+ box_search = False
+ cylinder_search = False
+ sphere_search = False
+ cone_search = False
+ tex_search = False ##################
+ cache = []
+ matrixes = {}
+ write_matrix = False
+ index = None
+ value = None
+ # file_pov = bpy.path.abspath(self.filepath) #was used for single files
+
+ def mat_search(cache):
+ r = g = b = 0.5
+ f = t = 0
+ color = None
+
+ for item, value in enumerate(cache):
+
+ if value == 'texture':
+ pass
+
+ if value == 'pigment':
+
+ if cache[item + 2] in {'rgb', 'srgb'}:
+ pass
+
+ elif cache[item + 2] in {'rgbf', 'srgbf'}:
+ pass
+
+ elif cache[item + 2] in {'rgbt', 'srgbt'}:
+ try:
+ r, g, b, t = (
+ float(cache[item + 3]),
+ float(cache[item + 4]),
+ float(cache[item + 5]),
+ float(cache[item + 6]),
+ )
+ except BaseException as e:
+ print(e.__doc__)
+ print('An exception occurred: {}'.format(e))
+ r = g = b = t = float(cache[item + 2])
+ color = (r, g, b, t)
+
+ elif cache[item + 2] in {'rgbft', 'srgbft'}:
+ pass
+
+ else:
+ pass
+
+ if colors == [] or (colors != [] and color not in colors):
+ colors.append(color)
+ name = ob.name + "_mat"
+ mat_names.append(name)
+ mat = bpy.data.materials.new(name)
+ mat.diffuse_color = (r, g, b)
+ mat.alpha = 1 - t
+ if mat.alpha != 1:
+ mat.use_transparency = True
+ ob.data.materials.append(mat)
+
+ else:
+ for i, value in enumerate(colors):
+ if color == value:
+ ob.data.materials.append(bpy.data.materials[mat_names[i]])
+
+ for file in self.files:
+ print("Importing file: " + file.name)
+ file_pov = self.directory + file.name
+ for line in open(file_pov):
+ string = line.replace("{", " ")
+ string = string.replace("}", " ")
+ string = string.replace("<", " ")
+ string = string.replace(">", " ")
+ string = string.replace(",", " ")
+ lw = string.split()
+ # lenwords = len(lw) # Not used... why written?
+ if lw:
+ if lw[0] == "object":
+ write_matrix = True
+ if write_matrix:
+ if lw[0] not in {"object", "matrix"}:
+ index = lw[0]
+ if lw[0] in {"matrix"}:
+ value = [
+ float(lw[1]),
+ float(lw[2]),
+ float(lw[3]),
+ float(lw[4]),
+ float(lw[5]),
+ float(lw[6]),
+ float(lw[7]),
+ float(lw[8]),
+ float(lw[9]),
+ float(lw[10]),
+ float(lw[11]),
+ float(lw[12]),
+ ]
+ matrixes[index] = value
+ write_matrix = False
+ for line in open(file_pov):
+ S = line.replace("{", " { ")
+ S = S.replace("}", " } ")
+ S = S.replace(",", " ")
+ S = S.replace("<", "")
+ S = S.replace(">", " ")
+ S = S.replace("=", " = ")
+ S = S.replace(";", " ; ")
+ S = S.split()
+ # lenS = len(S) # Not used... why written?
+ for i, word in enumerate(S):
+ ##################Primitives Import##################
+ if word == 'cone':
+ cone_search = True
+ name_search = False
+ if cone_search:
+ cache.append(word)
+ if cache[-1] == '}':
+ try:
+ x0 = float(cache[2])
+ y0 = float(cache[3])
+ z0 = float(cache[4])
+ r0 = float(cache[5])
+ x1 = float(cache[6])
+ y1 = float(cache[7])
+ z1 = float(cache[8])
+ r1 = float(cache[9])
+ # Y is height in most pov files, not z
+ bpy.ops.pov.cone_add(base=r0, cap=r1, height=(y1 - y0))
+ ob = context.object
+ ob.location = (x0, y0, z0)
+ # ob.scale = (r,r,r)
+ mat_search(cache)
+ except ValueError:
+ pass
+ cache = []
+ cone_search = False
+ if word == 'plane':
+ plane_search = True
+ name_search = False
+ if plane_search:
+ cache.append(word)
+ if cache[-1] == '}':
+ try:
+ bpy.ops.pov.addplane()
+ ob = context.object
+ mat_search(cache)
+ except ValueError:
+ pass
+ cache = []
+ plane_search = False
+ if word == 'box':
+ box_search = True
+ name_search = False
+ if box_search:
+ cache.append(word)
+ if cache[-1] == '}':
+ try:
+ x0 = float(cache[2])
+ y0 = float(cache[3])
+ z0 = float(cache[4])
+ x1 = float(cache[5])
+ y1 = float(cache[6])
+ z1 = float(cache[7])
+ # imported_corner_1=(x0, y0, z0)
+ # imported_corner_2 =(x1, y1, z1)
+ center = ((x0 + x1) / 2, (y0 + y1) / 2, (z0 + z1) / 2)
+ bpy.ops.pov.addbox()
+ ob = context.object
+ ob.location = center
+ mat_search(cache)
+
+ except ValueError:
+ pass
+ cache = []
+ box_search = False
+ if word == 'cylinder':
+ cylinder_search = True
+ name_search = False
+ if cylinder_search:
+ cache.append(word)
+ if cache[-1] == '}':
+ try:
+ x0 = float(cache[2])
+ y0 = float(cache[3])
+ z0 = float(cache[4])
+ x1 = float(cache[5])
+ y1 = float(cache[6])
+ z1 = float(cache[7])
+ imported_cyl_loc = (x0, y0, z0)
+ imported_cyl_loc_cap = (x1, y1, z1)
+
+ r = float(cache[8])
+
+ vec = Vector(imported_cyl_loc_cap) - Vector(imported_cyl_loc)
+ depth = vec.length
+ rot = Vector((0, 0, 1)).rotation_difference(
+ vec
+ ) # Rotation from Z axis.
+ trans = rot @ Vector( # XXX Not used, why written?
+ (0, 0, depth / 2)
+ ) # Such that origin is at center of the base of the cylinder.
+ # center = ((x0 + x1)/2,(y0 + y1)/2,(z0 + z1)/2)
+ scale_z = sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2 + (z1 - z0) ** 2) / 2
+ bpy.ops.pov.addcylinder(
+ R=r,
+ imported_cyl_loc=imported_cyl_loc,
+ imported_cyl_loc_cap=imported_cyl_loc_cap,
+ )
+ ob = context.object
+ ob.location = (x0, y0, z0)
+ ob.rotation_euler = rot.to_euler()
+ ob.scale = (1, 1, scale_z)
+
+ # scale data rather than obj?
+ # bpy.ops.object.mode_set(mode='EDIT')
+ # bpy.ops.mesh.reveal()
+ # bpy.ops.mesh.select_all(action='SELECT')
+ # bpy.ops.transform.resize(value=(1,1,scale_z), orient_type='LOCAL')
+ # bpy.ops.mesh.hide(unselected=False)
+ # bpy.ops.object.mode_set(mode='OBJECT')
+
+ mat_search(cache)
+
+ except ValueError:
+ pass
+ cache = []
+ cylinder_search = False
+ if word == 'sphere':
+ sphere_search = True
+ name_search = False
+ if sphere_search:
+ cache.append(word)
+ if cache[-1] == '}':
+ x = y = z = r = 0
+ try:
+ x = float(cache[2])
+ y = float(cache[3])
+ z = float(cache[4])
+ r = float(cache[5])
+
+ except ValueError:
+ pass
+ except:
+ x = y = z = float(cache[2])
+ r = float(cache[3])
+ bpy.ops.pov.addsphere(R=r, imported_loc=(x, y, z))
+ ob = context.object
+ ob.location = (x, y, z)
+ ob.scale = (r, r, r)
+ mat_search(cache)
+ cache = []
+ sphere_search = False
+ ##################End Primitives Import##################
+ if word == '#declare':
+ name_search = True
+ if name_search:
+ cache.append(word)
+ if word == 'mesh2':
+ name_search = False
+ if cache[-2] == '=':
+ name = cache[-3]
+ else:
+ suffix += 1
+ cache = []
+ if word in {'texture', ';'}:
+ name_search = False
+ cache = []
+ if word == 'vertex_vectors':
+ verts_search = True
+ if verts_search:
+ cache.append(word)
+ if word == '}':
+ verts_search = False
+ lenverts = cache[2]
+ cache.pop()
+ cache.pop(0)
+ cache.pop(0)
+ cache.pop(0)
+ for j in range(int(lenverts)):
+ x = j * 3
+ y = (j * 3) + 1
+ z = (j * 3) + 2
+ verts.append((float(cache[x]), float(cache[y]), float(cache[z])))
+ cache = []
+ # if word == 'face_indices':
+ # faces_search = True
+ if word == 'texture_list': ########
+ tex_search = True #######
+ if tex_search: #########
+ if (
+ word not in {'texture_list', 'texture', '{', '}', 'face_indices'}
+ and not word.isdigit()
+ ): ##############
+ pov_mats.append(word) #################
+ if word == 'face_indices':
+ tex_search = False ################
+ faces_search = True
+ if faces_search:
+ cache.append(word)
+ if word == '}':
+ faces_search = False
+ lenfaces = cache[2]
+ cache.pop()
+ cache.pop(0)
+ cache.pop(0)
+ cache.pop(0)
+ lf = int(lenfaces)
+ var = int(len(cache) / lf)
+ for k in range(lf):
+ if var == 3:
+ v0 = k * 3
+ v1 = k * 3 + 1
+ v2 = k * 3 + 2
+ faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
+ if var == 4:
+ v0 = k * 4
+ v1 = k * 4 + 1
+ v2 = k * 4 + 2
+ m = k * 4 + 3
+ materials.append((int(cache[m])))
+ faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
+ if var == 6:
+ v0 = k * 6
+ v1 = k * 6 + 1
+ v2 = k * 6 + 2
+ m0 = k * 6 + 3
+ m1 = k * 6 + 4
+ m2 = k * 6 + 5
+ materials.append(
+ (int(cache[m0]), int(cache[m1]), int(cache[m2]))
+ )
+ faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
+ # mesh = pov_define_mesh(None, verts, [], faces, name, hide_geometry=False)
+ # ob = object_utils.object_data_add(context, mesh, operator=None)
+
+ me = bpy.data.meshes.new(name) ########
+ ob = bpy.data.objects.new(name, me) ##########
+ bpy.context.collection.objects.link(ob) #########
+ me.from_pydata(verts, [], faces) ############
+
+ for mat in bpy.data.materials: ##############
+ blend_mats.append(mat.name) #############
+ for m_name in pov_mats: #####################
+ if m_name not in blend_mats: ###########
+ povMat = bpy.data.materials.new(m_name) #################
+ mat_search(cache)
+ ob.data.materials.append(
+ bpy.data.materials[m_name]
+ ) ###################
+ if materials: ##################
+ for l, val in enumerate(materials): ####################
+ try: ###################
+ ob.data.polygons[
+ l
+ ].material_index = val ####################
+ except TypeError: ###################
+ ob.data.polygons[l].material_index = int(
+ val[0]
+ ) ##################
+
+ blend_mats = [] #########################
+ pov_mats = [] #########################
+ materials = [] #########################
+ cache = []
+ name_search = True
+ if name in matrixes and not self.import_at_cur:
+ global_matrix = Matrix.Rotation(pi / 2.0, 4, 'X')
+ ob = bpy.context.object
+ matrix = ob.matrix_world
+ v = matrixes[name]
+ matrix[0][0] = v[0]
+ matrix[1][0] = v[1]
+ matrix[2][0] = v[2]
+ matrix[0][1] = v[3]
+ matrix[1][1] = v[4]
+ matrix[2][1] = v[5]
+ matrix[0][2] = v[6]
+ matrix[1][2] = v[7]
+ matrix[2][2] = v[8]
+ matrix[0][3] = v[9]
+ matrix[1][3] = v[10]
+ matrix[2][3] = v[11]
+ matrix = global_matrix * ob.matrix_world
+ ob.matrix_world = matrix
+ verts = []
+ faces = []
+
+ # if word == 'pigment':
+ # try:
+ # #all indices have been incremented once to fit a bad test file
+ # r,g,b,t = float(S[2]),float(S[3]),float(S[4]),float(S[5])
+ # color = (r,g,b,t)
+
+ # except IndexError:
+ # #all indices have been incremented once to fit alternate test file
+ # r,g,b,t = float(S[3]),float(S[4]),float(S[5]),float(S[6])
+ # color = (r,g,b,t)
+ # except UnboundLocalError:
+ # # In case no transmit is specified ? put it to 0
+ # r,g,b,t = float(S[2]),float(S[3]),float(S[4],0)
+ # color = (r,g,b,t)
+
+ # except ValueError:
+ # color = (0.8,0.8,0.8,0)
+ # pass
+
+ # if colors == [] or (colors != [] and color not in colors):
+ # colors.append(color)
+ # name = ob.name+"_mat"
+ # mat_names.append(name)
+ # mat = bpy.data.materials.new(name)
+ # mat.diffuse_color = (r,g,b)
+ # mat.alpha = 1-t
+ # if mat.alpha != 1:
+ # mat.use_transparency=True
+ # ob.data.materials.append(mat)
+ # print (colors)
+ # else:
+ # for m in range(len(colors)):
+ # if color == colors[m]:
+ # ob.data.materials.append(bpy.data.materials[mat_names[m]])
+
+ ##To keep Avogadro Camera angle:
+ # for obj in bpy.context.view_layer.objects:
+ # if obj.type == "CAMERA":
+ # track = obj.constraints.new(type = "TRACK_TO")
+ # track.target = ob
+ # track.track_axis ="TRACK_NEGATIVE_Z"
+ # track.up_axis = "UP_Y"
+ # obj.location = (0,0,0)
+ return {'FINISHED'}
+
+
+def register():
+ bpy.utils.register_class(ImportPOV)
+
+
+def unregister():
+ bpy.utils.unregister_class(ImportPOV)
diff --git a/render_povray/scripting_gui.py b/render_povray/scripting_gui.py
new file mode 100755
index 00000000..99006af1
--- /dev/null
+++ b/render_povray/scripting_gui.py
@@ -0,0 +1,268 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""User interface to POV Scene Description Language snippets or full includes:
+
+import, load, create or edit """
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import Operator, Menu, Panel
+from sys import platform # really import here, as in ui.py and in render.py?
+import os # really import here and in render.py?
+from os.path import isfile
+
+
+def locate_docpath():
+ """POV can be installed with some include files.
+
+ Get their path as defined in user preferences or registry keys for
+ the user to be able to invoke them."""
+
+ addon_prefs = bpy.context.preferences.addons[__package__].preferences
+ # Use the system preference if its set.
+ pov_documents = addon_prefs.docpath_povray
+ if pov_documents:
+ if os.path.exists(pov_documents):
+ return pov_documents
+ # Implicit else, as here return was still not triggered:
+ print(
+ "User Preferences path to povray documents %r NOT FOUND, checking $PATH" % pov_documents
+ )
+
+ # Windows Only
+ if platform.startswith('win'):
+ import winreg
+
+ try:
+ win_reg_key = winreg.OpenKey(
+ winreg.HKEY_CURRENT_USER, "Software\\POV-Ray\\v3.7\\Windows"
+ )
+ win_docpath = winreg.QueryValueEx(win_reg_key, "DocPath")[0]
+ pov_documents = os.path.join(win_docpath, "Insert Menu")
+ if os.path.exists(pov_documents):
+ return pov_documents
+ except FileNotFoundError:
+ return ""
+ # search the path all os's
+ pov_documents_default = "include"
+
+ os_path_ls = os.getenv("PATH").split(':') + [""]
+
+ for dir_name in os_path_ls:
+ pov_documents = os.path.join(dir_name, pov_documents_default)
+ if os.path.exists(pov_documents):
+ return pov_documents
+ return ""
+
+
+################################################################################
+class TextButtonsPanel:
+ """Use this class to define buttons from the side tab of
+ text window."""
+
+ bl_space_type = 'TEXT_EDITOR'
+ bl_region_type = 'UI'
+ bl_label = "POV-Ray"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ text = context.space_data
+ rd = context.scene.render
+ return text and (rd.engine in cls.COMPAT_ENGINES)
+
+
+###############################################################################
+# Text Povray Settings
+###############################################################################
+
+
+class TEXT_OT_POV_insert(Operator):
+ """Use this class to create blender text editor operator to insert pov snippets like other pov IDEs"""
+
+ bl_idname = "text.povray_insert"
+ bl_label = "Insert"
+
+ filepath: bpy.props.StringProperty(name="Filepath", subtype='FILE_PATH')
+
+ @classmethod
+ def poll(cls, context):
+ text = context.space_data.text
+ return context.area.type == 'TEXT_EDITOR' and text is not None
+ # return bpy.ops.text.insert.poll() this Bpy op has no poll()
+
+ def execute(self, context):
+ if self.filepath and isfile(self.filepath):
+ file = open(self.filepath, "r")
+ bpy.ops.text.insert(text=file.read())
+
+ # places the cursor at the end without scrolling -.-
+ # context.space_data.text.write(file.read())
+ file.close()
+ return {'FINISHED'}
+
+
+def validinsert(ext):
+ """Since preview images could be in same folder, filter only insertable text"""
+ return ext in {".txt", ".inc", ".pov"}
+
+
+class TEXT_MT_POV_insert(Menu):
+ """Use this class to create a menu launcher in text editor for the TEXT_OT_POV_insert operator ."""
+
+ bl_label = "Insert"
+ bl_idname = "TEXT_MT_POV_insert"
+
+ def draw(self, context):
+ pov_documents = locate_docpath()
+ prop = self.layout.operator("wm.path_open", text="Open folder", icon='FILE_FOLDER')
+ prop.filepath = pov_documents
+ self.layout.separator()
+
+ pov_insert_items_list = []
+ for root, dirs, files in os.walk(pov_documents): # todo: structure submenus by dir
+ pov_insert_items_list.append(root)
+ print(pov_insert_items_list)
+ self.path_menu(
+ pov_insert_items_list,
+ "text.povray_insert",
+ # {"internal": True},
+ filter_ext=validinsert,
+ )
+
+
+class TEXT_PT_POV_custom_code(TextButtonsPanel, Panel):
+ """Use this class to create a panel in text editor for the user to decide if he renders text
+
+ only or adds to 3d scene."""
+
+ bl_label = "POV"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ text = context.space_data.text
+
+ pov_documents = locate_docpath()
+ if not pov_documents:
+ layout.label(text="Please configure ", icon="INFO")
+ layout.label(text="default pov include path ")
+ layout.label(text="in addon preferences")
+ # layout.separator()
+ layout.operator(
+ "preferences.addon_show",
+ text="Go to Render: Persistence of Vision addon",
+ icon="PREFERENCES",
+ ).module = "render_povray"
+
+ # layout.separator()
+ else:
+ # print(pov_documents)
+ layout.menu(TEXT_MT_POV_insert.bl_idname)
+
+ if text:
+ box = layout.box()
+ box.label(text='Source to render:', icon='RENDER_STILL')
+ row = box.row()
+ row.prop(text.pov, "custom_code", expand=True)
+ if text.pov.custom_code in {'3dview'}:
+ box.operator("render.render", icon='OUTLINER_DATA_ARMATURE')
+ if text.pov.custom_code in {'text'}:
+ rtext = bpy.context.space_data.text # is r a typo ? or why written, not used
+ box.operator("text.run", icon='ARMATURE_DATA')
+ # layout.prop(text.pov, "custom_code")
+ elif text.pov.custom_code in {'both'}:
+ box.operator("render.render", icon='POSE_HLT')
+ layout.label(text="Please specify declared", icon="INFO")
+ layout.label(text="items in properties ")
+ # layout.label(text="")
+ layout.label(text="replacement fields")
+
+
+###############################################
+# Text editor templates from header menu
+
+
+class TEXT_MT_POV_templates(Menu):
+ """Use this class to create a menu for the same pov templates scenes as other pov IDEs."""
+
+ bl_label = "POV"
+
+ # We list templates on file evaluation, we can assume they are static data,
+ # and better avoid running this on every draw call.
+ template_paths = [os.path.join(os.path.dirname(__file__), "templates_pov")]
+
+ def draw(self, context):
+ self.path_menu(self.template_paths, "text.open", props_default={"internal": True})
+
+
+def menu_func_templates(self, context):
+ """Add POV files to the text editor templates menu"""
+ # Do not depend on POV being active renderer here...
+ self.layout.menu("TEXT_MT_POV_templates")
+
+
+###############################################
+# POV Import menu
+class VIEW_MT_POV_import(Menu):
+ """Use this class for the import menu."""
+
+ bl_idname = "POVRAY_MT_import_tools"
+ bl_label = "Import"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
+
+
+def menu_func_import(self, context):
+ """Add the import operator to menu"""
+ engine = context.scene.render.engine
+ if engine == 'POVRAY_RENDER':
+ self.layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
+
+
+classes = (
+ VIEW_MT_POV_import,
+ TEXT_OT_POV_insert,
+ TEXT_MT_POV_insert,
+ TEXT_PT_POV_custom_code,
+ TEXT_MT_POV_templates,
+)
+
+
+def register():
+
+ for cls in classes:
+ register_class(cls)
+
+ bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
+ bpy.types.TEXT_MT_templates.append(menu_func_templates)
+
+
+def unregister():
+
+ bpy.types.TEXT_MT_templates.remove(menu_func_templates)
+ bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
+
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/scripting_properties.py b/render_povray/scripting_properties.py
new file mode 100755
index 00000000..3e743da3
--- /dev/null
+++ b/render_povray/scripting_properties.py
@@ -0,0 +1,57 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+
+"""Declare pov native file syntax properties controllable in UI hooks and text blocks"""
+
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import EnumProperty, PointerProperty
+
+###############################################################################
+# Text POV properties.
+###############################################################################
+
+
+class RenderPovSettingsText(PropertyGroup):
+
+ """Declare text properties to use UI as an IDE or render text snippets to POV."""
+
+ custom_code: EnumProperty(
+ name="Custom Code",
+ description="rendered source: Both adds text at the " "top of the exported POV file",
+ items=(("3dview", "View", ""), ("text", "Text", ""), ("both", "Both", "")),
+ default="text",
+ )
+
+
+classes = (RenderPovSettingsText,)
+
+
+def register():
+ for cls in classes:
+ register_class(cls)
+ bpy.types.Text.pov = PointerProperty(type=RenderPovSettingsText)
+
+
+def unregister():
+ del bpy.types.Text.pov
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/shading.py b/render_povray/shading.py
index a3f907dc..680be99c 100644..100755
--- a/render_povray/shading.py
+++ b/render_povray/shading.py
@@ -22,248 +22,366 @@
import bpy
-def writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments, uniqueName, materialNames, material):
+
+def write_object_material(material, ob, tab_write):
+ """Translate some object level material from Blender UI (VS data level)
+
+ to POV interior{} syntax and write it to exported file.
+ """
+ # DH - modified some variables to be function local, avoiding RNA write
+ # this should be checked to see if it is functionally correct
+
+ # Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
+ # if material and material.transparency_method == 'RAYTRACE':
+ if material:
+ # But there can be only one!
+ if material.pov_subsurface_scattering.use: # SSS IOR get highest priority
+ tab_write("interior {\n")
+ tab_write("ior %.6f\n" % material.pov_subsurface_scattering.ior)
+ # Then the raytrace IOR taken from raytrace transparency properties and used for
+ # reflections if IOR Mirror option is checked.
+ elif material.pov.mirror_use_IOR:
+ tab_write("interior {\n")
+ tab_write("ior %.6f\n" % material.pov_raytrace_transparency.ior)
+ elif material.pov.transparency_method == 'Z_TRANSPARENCY':
+ tab_write("interior {\n")
+ tab_write("ior 1.0\n")
+ else:
+ tab_write("interior {\n")
+ tab_write("ior %.6f\n" % material.pov_raytrace_transparency.ior)
+
+ pov_fake_caustics = False
+ pov_photons_refraction = False
+ pov_photons_reflection = False
+
+ if material.pov.photons_reflection:
+ pov_photons_reflection = True
+ if not material.pov.refraction_caustics:
+ pov_fake_caustics = False
+ pov_photons_refraction = False
+ elif material.pov.refraction_type == "1":
+ pov_fake_caustics = True
+ pov_photons_refraction = False
+ elif material.pov.refraction_type == "2":
+ pov_fake_caustics = False
+ pov_photons_refraction = True
+
+ # If only Raytrace transparency is set, its IOR will be used for refraction, but user
+ # can set up 'un-physical' fresnel reflections in raytrace mirror parameters.
+ # Last, if none of the above is specified, user can set up 'un-physical' fresnel
+ # reflections in raytrace mirror parameters. And pov IOR defaults to 1.
+ if material.pov.caustics_enable:
+ if pov_fake_caustics:
+ tab_write("caustics %.3g\n" % material.pov.fake_caustics_power)
+ if pov_photons_refraction:
+ # Default of 1 means no dispersion
+ tab_write("dispersion %.6f\n" % material.pov.photons_dispersion)
+ tab_write("dispersion_samples %.d\n" % material.pov.photons_dispersion_samples)
+ # TODO
+ # Other interior args
+ if material.pov.use_transparency and material.pov.transparency_method == 'RAYTRACE':
+ # fade_distance
+ # In Blender this value has always been reversed compared to what tooltip says.
+ # 100.001 rather than 100 so that it does not get to 0
+ # which deactivates the feature in POV
+ tab_write(
+ "fade_distance %.3g\n" % (100.001 - material.pov_raytrace_transparency.depth_max)
+ )
+ # fade_power
+ tab_write("fade_power %.3g\n" % material.pov_raytrace_transparency.falloff)
+ # fade_color
+ tab_write("fade_color <%.3g, %.3g, %.3g>\n" % material.pov.interior_fade_color[:])
+
+ # (variable) dispersion_samples (constant count for now)
+ tab_write("}\n")
+ if material.pov.photons_reflection or material.pov.refraction_type == "2":
+ tab_write("photons{")
+ tab_write("target %.3g\n" % ob.pov.spacing_multiplier)
+ if not ob.pov.collect_photons:
+ tab_write("collect off\n")
+ if pov_photons_refraction:
+ tab_write("refraction on\n")
+ if pov_photons_reflection:
+ tab_write("reflection on\n")
+ tab_write("}\n")
+
+
+def write_material(
+ using_uberpov, DEF_MAT_NAME, tab_write, safety, comments, unique_name, material_names, material
+):
"""Translate Blender material POV texture{} block and write to exported file."""
# Assumes only called once on each material
if material:
name_orig = material.name
- name = materialNames[name_orig] = uniqueName(bpy.path.clean_name(name_orig), materialNames)
+ name = material_names[name_orig] = unique_name(
+ bpy.path.clean_name(name_orig), material_names
+ )
else:
name = name_orig = DEF_MAT_NAME
-
if material:
# If saturation(.s) is not zero, then color is not grey, and has a tint
- colored_specular_found = ((material.pov.specular_color.s > 0.0) and (material.pov.diffuse_shader != 'MINNAERT'))
+ colored_specular_found = (material.pov.specular_color.s > 0.0) and (
+ material.pov.diffuse_shader != "MINNAERT"
+ )
##################
- # Several versions of the finish: Level conditions are variations for specular/Mirror
+ # Several versions of the finish: ref_level_bound conditions are variations for specular/Mirror
# texture channel map with alternative finish of 0 specular and no mirror reflection.
- # Level=1 Means No specular nor Mirror reflection
- # Level=2 Means translation of spec and mir levels for when no map influences them
- # Level=3 Means Maximum Spec and Mirror
+ # ref_level_bound=1 Means No specular nor Mirror reflection
+ # ref_level_bound=2 Means translation of spec and mir levels for when no map influences them
+ # ref_level_bound=3 Means Maximum Spec and Mirror
- def povHasnoSpecularMaps(Level):
+ def pov_has_no_specular_maps(ref_level_bound):
"""Translate Blender specular map influence to POV finish map trick and write to file."""
- if Level == 1:
+ if ref_level_bound == 1:
if comments:
- tabWrite("//--No specular nor Mirror reflection--\n")
+ tab_write("//--No specular nor Mirror reflection--\n")
else:
- tabWrite("\n")
- tabWrite("#declare %s = finish {\n" % safety(name, Level=1))
+ tab_write("\n")
+ tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=1))
- elif Level == 2:
+ elif ref_level_bound == 2:
if comments:
- tabWrite("//--translation of spec and mir levels for when no map " \
- "influences them--\n")
+ tab_write(
+ "//--translation of spec and mir levels for when no map " "influences them--\n"
+ )
else:
- tabWrite("\n")
- tabWrite("#declare %s = finish {\n" % safety(name, Level=2))
+ tab_write("\n")
+ tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=2))
- elif Level == 3:
+ elif ref_level_bound == 3:
if comments:
- tabWrite("//--Maximum Spec and Mirror--\n")
+ tab_write("//--Maximum Spec and Mirror--\n")
else:
- tabWrite("\n")
- tabWrite("#declare %s = finish {\n" % safety(name, Level=3))
+ tab_write("\n")
+ tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=3))
if material:
# POV-Ray 3.7 now uses two diffuse values respectively for front and back shading
# (the back diffuse is like blender translucency)
- frontDiffuse = material.pov.diffuse_intensity
- backDiffuse = material.pov.translucency
+ front_diffuse = material.pov.diffuse_intensity
+ back_diffuse = material.pov.translucency
if material.pov.conserve_energy:
- #Total should not go above one
- if (frontDiffuse + backDiffuse) <= 1.0:
+ # Total should not go above one
+ if (front_diffuse + back_diffuse) <= 1.0:
pass
- elif frontDiffuse == backDiffuse:
+ elif front_diffuse == back_diffuse:
# Try to respect the user's 'intention' by comparing the two values but
# bringing the total back to one.
- frontDiffuse = backDiffuse = 0.5
+ front_diffuse = back_diffuse = 0.5
# Let the highest value stay the highest value.
- elif frontDiffuse > backDiffuse:
+ elif front_diffuse > back_diffuse:
# clamps the sum below 1
- backDiffuse = min(backDiffuse, (1.0 - frontDiffuse))
+ back_diffuse = min(back_diffuse, (1.0 - front_diffuse))
else:
- frontDiffuse = min(frontDiffuse, (1.0 - backDiffuse))
+ front_diffuse = min(front_diffuse, (1.0 - back_diffuse))
# map hardness between 0.0 and 1.0
- roughness = ((1.0 - ((material.pov.specular_hardness - 1.0) / 510.0)))
+ roughness = 1.0 - ((material.pov.specular_hardness - 1.0) / 510.0)
## scale from 0.0 to 0.1
roughness *= 0.1
# add a small value because 0.0 is invalid.
- roughness += (1.0 / 511.0)
+ roughness += 1.0 / 511.0
################################Diffuse Shader######################################
- # Not used for Full spec (Level=3) of the shader.
- if material.pov.diffuse_shader == 'OREN_NAYAR' and Level != 3:
+ # Not used for Full spec (ref_level_bound=3) of the shader.
+ if material.pov.diffuse_shader == "OREN_NAYAR" and ref_level_bound != 3:
# Blender roughness is what is generally called oren nayar Sigma,
# and brilliance in POV-Ray.
- tabWrite("brilliance %.3g\n" % (0.9 + material.roughness))
+ tab_write("brilliance %.3g\n" % (0.9 + material.roughness))
- if material.pov.diffuse_shader == 'TOON' and Level != 3:
- tabWrite("brilliance %.3g\n" % (0.01 + material.diffuse_toon_smooth * 0.25))
+ if material.pov.diffuse_shader == "TOON" and ref_level_bound != 3:
+ tab_write("brilliance %.3g\n" % (0.01 + material.diffuse_toon_smooth * 0.25))
# Lower diffuse and increase specular for toon effect seems to look better
# in POV-Ray.
- frontDiffuse *= 0.5
+ front_diffuse *= 0.5
- if material.pov.diffuse_shader == 'MINNAERT' and Level != 3:
- #tabWrite("aoi %.3g\n" % material.darkness)
+ if material.pov.diffuse_shader == "MINNAERT" and ref_level_bound != 3:
+ # tab_write("aoi %.3g\n" % material.darkness)
pass # let's keep things simple for now
- if material.pov.diffuse_shader == 'FRESNEL' and Level != 3:
- #tabWrite("aoi %.3g\n" % material.diffuse_fresnel_factor)
+ if material.pov.diffuse_shader == "FRESNEL" and ref_level_bound != 3:
+ # tab_write("aoi %.3g\n" % material.diffuse_fresnel_factor)
pass # let's keep things simple for now
- if material.pov.diffuse_shader == 'LAMBERT' and Level != 3:
+ if material.pov.diffuse_shader == "LAMBERT" and ref_level_bound != 3:
# trying to best match lambert attenuation by that constant brilliance value
- tabWrite("brilliance 1\n")
+ tab_write("brilliance 1\n")
- if Level == 2:
+ if ref_level_bound == 2:
###########################Specular Shader######################################
# No difference between phong and cook torrence in blender HaHa!
- if (material.pov.specular_shader == 'COOKTORR' or
- material.pov.specular_shader == 'PHONG'):
- tabWrite("phong %.3g\n" % (material.pov.specular_intensity))
- tabWrite("phong_size %.3g\n" % (material.pov.specular_hardness /3.14))
+ if (
+ material.pov.specular_shader == "COOKTORR"
+ or material.pov.specular_shader == "PHONG"
+ ):
+ tab_write("phong %.3g\n" % (material.pov.specular_intensity))
+ tab_write("phong_size %.3g\n" % (material.pov.specular_hardness / 3.14))
# POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
- elif material.pov.specular_shader == 'BLINN':
+ elif material.pov.specular_shader == "BLINN":
# Use blender Blinn's IOR just as some factor for spec intensity
- tabWrite("specular %.3g\n" % (material.pov.specular_intensity *
- (material.pov.specular_ior / 4.0)))
- tabWrite("roughness %.3g\n" % roughness)
- #Could use brilliance 2(or varying around 2 depending on ior or factor) too.
-
- elif material.pov.specular_shader == 'TOON':
- tabWrite("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
+ tab_write(
+ "specular %.3g\n"
+ % (material.pov.specular_intensity * (material.pov.specular_ior / 4.0))
+ )
+ tab_write("roughness %.3g\n" % roughness)
+ # Could use brilliance 2(or varying around 2 depending on ior or factor) too.
+
+ elif material.pov.specular_shader == "TOON":
+ tab_write("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
# use extreme phong_size
- tabWrite("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
+ tab_write("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
- elif material.pov.specular_shader == 'WARDISO':
+ elif material.pov.specular_shader == "WARDISO":
# find best suited default constant for brilliance Use both phong and
# specular for some values.
- tabWrite("specular %.3g\n" % (material.pov.specular_intensity /
- (material.pov.specular_slope + 0.0005)))
+ tab_write(
+ "specular %.3g\n"
+ % (material.pov.specular_intensity / (material.pov.specular_slope + 0.0005))
+ )
# find best suited default constant for brilliance Use both phong and
# specular for some values.
- tabWrite("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
+ tab_write("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
# find best suited default constant for brilliance Use both phong and
# specular for some values.
- tabWrite("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
+ tab_write("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
####################################################################################
- elif Level == 1:
- if (material.pov.specular_shader == 'COOKTORR' or
- material.pov.specular_shader == 'PHONG'):
- tabWrite("phong 0\n")#%.3g\n" % (material.pov.specular_intensity/5))
- tabWrite("phong_size %.3g\n" % (material.pov.specular_hardness /3.14))
+ elif ref_level_bound == 1:
+ if (
+ material.pov.specular_shader == "COOKTORR"
+ or material.pov.specular_shader == "PHONG"
+ ):
+ tab_write("phong 0\n") #%.3g\n" % (material.pov.specular_intensity/5))
+ tab_write("phong_size %.3g\n" % (material.pov.specular_hardness / 3.14))
# POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
- elif material.pov.specular_shader == 'BLINN':
+ elif material.pov.specular_shader == "BLINN":
# Use blender Blinn's IOR just as some factor for spec intensity
- tabWrite("specular %.3g\n" % (material.pov.specular_intensity *
- (material.pov.specular_ior / 4.0)))
- tabWrite("roughness %.3g\n" % roughness)
- #Could use brilliance 2(or varying around 2 depending on ior or factor) too.
-
- elif material.pov.specular_shader == 'TOON':
- tabWrite("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
+ tab_write(
+ "specular %.3g\n"
+ % (material.pov.specular_intensity * (material.pov.specular_ior / 4.0))
+ )
+ tab_write("roughness %.3g\n" % roughness)
+ # Could use brilliance 2(or varying around 2 depending on ior or factor) too.
+
+ elif material.pov.specular_shader == "TOON":
+ tab_write("phong %.3g\n" % (material.pov.specular_intensity * 2.0))
# use extreme phong_size
- tabWrite("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
+ tab_write("phong_size %.3g\n" % (0.1 + material.pov.specular_toon_smooth / 2.0))
- elif material.pov.specular_shader == 'WARDISO':
+ elif material.pov.specular_shader == "WARDISO":
# find best suited default constant for brilliance Use both phong and
# specular for some values.
- tabWrite("specular %.3g\n" % (material.pov.specular_intensity /
- (material.pov.specular_slope + 0.0005)))
+ tab_write(
+ "specular %.3g\n"
+ % (material.pov.specular_intensity / (material.pov.specular_slope + 0.0005))
+ )
# find best suited default constant for brilliance Use both phong and
# specular for some values.
- tabWrite("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
+ tab_write("roughness %.4g\n" % (0.0005 + material.pov.specular_slope / 10.0))
# find best suited default constant for brilliance Use both phong and
# specular for some values.
- tabWrite("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
- elif Level == 3:
- # Spec must be Max at Level 3 so that white of mixing texture always shows specularity
+ tab_write("brilliance %.4g\n" % (1.8 - material.pov.specular_slope * 1.8))
+ elif ref_level_bound == 3:
+ # Spec must be Max at ref_level_bound 3 so that white of mixing texture always shows specularity
# That's why it's multiplied by 255. maybe replace by texture's brightest pixel value?
- tabWrite("specular %.3g\n" % ((material.pov.specular_intensity*material.pov.specular_color.v)*(255* slot.specular_factor)))
- tabWrite("roughness %.3g\n" % (1/material.pov.specular_hardness))
- tabWrite("diffuse %.3g %.3g\n" % (frontDiffuse, backDiffuse))
-
- tabWrite("ambient %.3g\n" % material.pov.ambient)
+ tab_write(
+ "specular %.3g\n"
+ % (
+ (material.pov.specular_intensity * material.pov.specular_color.v)
+ * (255 * slot.specular_factor)
+ )
+ )
+ tab_write("roughness %.3g\n" % (1 / material.pov.specular_hardness))
+ tab_write("diffuse %.3g %.3g\n" % (front_diffuse, back_diffuse))
+
+ tab_write("ambient %.3g\n" % material.pov.ambient)
# POV-Ray blends the global value
- #tabWrite("ambient rgb <%.3g, %.3g, %.3g>\n" % \
+ # tab_write("ambient rgb <%.3g, %.3g, %.3g>\n" % \
# tuple([c*material.pov.ambient for c in world.ambient_color]))
- tabWrite("emission %.3g\n" % material.pov.emit) # New in POV-Ray 3.7
+ tab_write("emission %.3g\n" % material.pov.emit) # New in POV-Ray 3.7
- #POV-Ray just ignores roughness if there's no specular keyword
- #tabWrite("roughness %.3g\n" % roughness)
+ # POV-Ray just ignores roughness if there's no specular keyword
+ # tab_write("roughness %.3g\n" % roughness)
if material.pov.conserve_energy:
# added for more realistic shading. Needs some checking to see if it
# really works. --Maurice.
- tabWrite("conserve_energy\n")
+ tab_write("conserve_energy\n")
- if colored_specular_found == True:
- tabWrite("metallic\n")
+ if colored_specular_found:
+ tab_write("metallic\n")
# 'phong 70.0 '
- if Level != 1:
+ if ref_level_bound != 1:
if material.pov_raytrace_mirror.use:
raytrace_mirror = material.pov_raytrace_mirror
if raytrace_mirror.reflect_factor:
- tabWrite("reflection {\n")
- tabWrite("rgb <%.3g, %.3g, %.3g>\n" % material.pov.mirror_color[:])
+ tab_write("reflection {\n")
+ tab_write("rgb <%.3g, %.3g, %.3g>\n" % material.pov.mirror_color[:])
if material.pov.mirror_metallic:
- tabWrite("metallic %.3g\n" % (raytrace_mirror.reflect_factor))
+ tab_write("metallic %.3g\n" % (raytrace_mirror.reflect_factor))
# Blurry reflections for UberPOV
if using_uberpov and raytrace_mirror.gloss_factor < 1.0:
- #tabWrite("#ifdef(unofficial) #if(unofficial = \"patch\") #if(patch(\"upov-reflection-roughness\") > 0)\n")
- tabWrite("roughness %.6f\n" % \
- (0.000001/raytrace_mirror.gloss_factor))
- #tabWrite("#end #end #end\n") # This and previous comment for backward compatibility, messier pov code
+ # tab_write("#ifdef(unofficial) #if(unofficial = \"patch\") #if(patch(\"upov-reflection-roughness\") > 0)\n")
+ tab_write(
+ "roughness %.6f\n" % (0.000001 / raytrace_mirror.gloss_factor)
+ )
+ # tab_write("#end #end #end\n") # This and previous comment for backward compatibility, messier pov code
if material.pov.mirror_use_IOR: # WORKING ?
# Removed from the line below: gives a more physically correct
# material but needs proper IOR. --Maurice
- tabWrite("fresnel 1 ")
- tabWrite("falloff %.3g exponent %.3g} " % \
- (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor))
+ tab_write("fresnel 1 ")
+ tab_write(
+ "falloff %.3g exponent %.3g} "
+ % (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor)
+ )
if material.pov_subsurface_scattering.use:
subsurface_scattering = material.pov_subsurface_scattering
- tabWrite("subsurface { translucency <%.3g, %.3g, %.3g> }\n" % (
- (subsurface_scattering.radius[0]),
- (subsurface_scattering.radius[1]),
- (subsurface_scattering.radius[2]),
- )
- )
+ tab_write(
+ "subsurface { translucency <%.3g, %.3g, %.3g> }\n"
+ % (
+ (subsurface_scattering.radius[0]),
+ (subsurface_scattering.radius[1]),
+ (subsurface_scattering.radius[2]),
+ )
+ )
if material.pov.irid_enable:
- tabWrite("irid { %.4g thickness %.4g turbulence %.4g }" % \
- (material.pov.irid_amount, material.pov.irid_thickness,
- material.pov.irid_turbulence))
+ tab_write(
+ "irid { %.4g thickness %.4g turbulence %.4g }"
+ % (
+ material.pov.irid_amount,
+ material.pov.irid_thickness,
+ material.pov.irid_turbulence,
+ )
+ )
else:
- tabWrite("diffuse 0.8\n")
- tabWrite("phong 70.0\n")
+ tab_write("diffuse 0.8\n")
+ tab_write("phong 70.0\n")
- #tabWrite("specular 0.2\n")
+ # tab_write("specular 0.2\n")
# This is written into the object
- '''
+ """
if material and material.pov.transparency_method=='RAYTRACE':
'interior { ior %.3g} ' % material.raytrace_transparency.ior
- '''
+ """
- #tabWrite("crand 1.0\n") # Sand granyness
- #tabWrite("metallic %.6f\n" % material.spec)
- #tabWrite("phong %.6f\n" % material.spec)
- #tabWrite("phong_size %.6f\n" % material.spec)
- #tabWrite("brilliance %.6f " % (material.pov.specular_hardness/256.0) # Like hardness
+ # tab_write("crand 1.0\n") # Sand granyness
+ # tab_write("metallic %.6f\n" % material.spec)
+ # tab_write("phong %.6f\n" % material.spec)
+ # tab_write("phong_size %.6f\n" % material.spec)
+ # tab_write("brilliance %.6f " % (material.pov.specular_hardness/256.0) # Like hardness
- tabWrite("}\n\n")
+ tab_write("}\n\n")
- # Level=2 Means translation of spec and mir levels for when no map influences them
- povHasnoSpecularMaps(Level=2)
+ # ref_level_bound=2 Means translation of spec and mir levels for when no map influences them
+ pov_has_no_specular_maps(ref_level_bound=2)
if material:
special_texture_found = False
@@ -271,1495 +389,1181 @@ def writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments
for t in material.pov_texture_slots:
tmpidx += 1
# index = material.pov.active_texture_index
- slot = material.pov_texture_slots[tmpidx] # [index]
- povtex = slot.texture # slot.name
+ slot = material.pov_texture_slots[tmpidx] # [index]
+ povtex = slot.texture # slot.name
tex = bpy.data.textures[povtex]
if t and t.use and tex is not None:
-
- if (tex.type == 'IMAGE' and tex.image) or tex.type != 'IMAGE':
- #validPath
- if(t and t.use and
- (t.use_map_specular or t.use_map_raymir or t.use_map_normal or t.use_map_alpha)):
+ if (tex.type == "IMAGE" and tex.image) or tex.type != "IMAGE":
+ # validPath
+ if (
+ t
+ and t.use
+ and (
+ t.use_map_specular
+ or t.use_map_raymir
+ or t.use_map_normal
+ or t.use_map_alpha
+ )
+ ):
special_texture_found = True
continue # Some texture found
if special_texture_found or colored_specular_found:
- # Level=1 Means No specular nor Mirror reflection
- povHasnoSpecularMaps(Level=1)
+ # ref_level_bound=1 Means No specular nor Mirror reflection
+ pov_has_no_specular_maps(ref_level_bound=1)
+
+ # ref_level_bound=3 Means Maximum Spec and Mirror
+ pov_has_no_specular_maps(ref_level_bound=3)
- # Level=3 Means Maximum Spec and Mirror
- povHasnoSpecularMaps(Level=3)
-def exportPattern(texture, string_strip_hyphen):
+def export_pattern(texture):
"""Translate Blender procedural textures to POV patterns and write to pov file.
Function Patterns can be used to better access sub components of a pattern like
- grey values for influence mapping"""
-
- tex=texture
+ grey values for influence mapping
+ """
+ tex = texture
pat = tex.pov
- PATname = "PAT_%s"%string_strip_hyphen(bpy.path.clean_name(tex.name))
- mappingDif = ("translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>" % \
- (pat.tex_mov_x, pat.tex_mov_y, pat.tex_mov_z,
- 1.0 / pat.tex_scale_x, 1.0 / pat.tex_scale_y, 1.0 / pat.tex_scale_z))
- texStrg=""
- def exportColorRamp(texture):
- tex=texture
+ pat_name = "PAT_%s" % string_strip_hyphen(bpy.path.clean_name(tex.name))
+ mapping_dif = "translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>" % (
+ pat.tex_mov_x,
+ pat.tex_mov_y,
+ pat.tex_mov_z,
+ 1.0 / pat.tex_scale_x,
+ 1.0 / pat.tex_scale_y,
+ 1.0 / pat.tex_scale_z,
+ )
+ text_strg = ""
+
+ def export_color_ramp(texture):
+ tex = texture
pat = tex.pov
- colRampStrg="color_map {\n"
- numColor=0
+ col_ramp_strg = "color_map {\n"
+ num_color = 0
for el in tex.color_ramp.elements:
- numColor+=1
+ num_color += 1
pos = el.position
- col=el.color
- colR,colG,colB,colA = col[0],col[1],col[2],1-col[3]
- if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
- colRampStrg+="[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n"%(pos,colR,colG,colB,colA)
- if pat.tex_pattern_type in {'brick','checker'} and numColor < 3:
- colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
- if pat.tex_pattern_type == 'hexagon' and numColor < 4 :
- colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
- if pat.tex_pattern_type == 'square' and numColor < 5 :
- colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
- if pat.tex_pattern_type == 'triangular' and numColor < 7 :
- colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
-
- colRampStrg+="} \n"
- #end color map
- return colRampStrg
- #much work to be done here only defaults translated for now:
- #pov noise_generator 3 means perlin noise
- if tex.type not in {'NONE', 'IMAGE'} and pat.tex_pattern_type == 'emulator':
- texStrg+="pigment {\n"
+ col = el.color
+ col_r, col_g, col_b, col_a = col[0], col[1], col[2], 1 - col[3]
+ if pat.tex_pattern_type not in {"checker", "hexagon", "square", "triangular", "brick"}:
+ col_ramp_strg += "[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n" % (
+ pos,
+ col_r,
+ col_g,
+ col_b,
+ col_a,
+ )
+ if pat.tex_pattern_type in {"brick", "checker"} and num_color < 3:
+ col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+ if pat.tex_pattern_type == "hexagon" and num_color < 4:
+ col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+ if pat.tex_pattern_type == "square" and num_color < 5:
+ col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+ if pat.tex_pattern_type == "triangular" and num_color < 7:
+ col_ramp_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+
+ col_ramp_strg += "} \n"
+ # end color map
+ return col_ramp_strg
+
+ # much work to be done here only defaults translated for now:
+ # pov noise_generator 3 means perlin noise
+ if tex.type not in {"NONE", "IMAGE"} and pat.tex_pattern_type == "emulator":
+ text_strg += "pigment {\n"
####################### EMULATE BLENDER VORONOI TEXTURE ####################
- if tex.type == 'VORONOI':
- texStrg+="crackle\n"
- texStrg+=" offset %.4g\n"%tex.nabla
- texStrg+=" form <%.4g,%.4g,%.4g>\n"%(tex.weight_1, tex.weight_2, tex.weight_3)
- if tex.distance_metric == 'DISTANCE':
- texStrg+=" metric 2.5\n"
- if tex.distance_metric == 'DISTANCE_SQUARED':
- texStrg+=" metric 2.5\n"
- texStrg+=" poly_wave 2\n"
- if tex.distance_metric == 'MINKOVSKY':
- texStrg+=" metric %s\n"%tex.minkovsky_exponent
- if tex.distance_metric == 'MINKOVSKY_FOUR':
- texStrg+=" metric 4\n"
- if tex.distance_metric == 'MINKOVSKY_HALF':
- texStrg+=" metric 0.5\n"
- if tex.distance_metric == 'CHEBYCHEV':
- texStrg+=" metric 10\n"
- if tex.distance_metric == 'MANHATTAN':
- texStrg+=" metric 1\n"
-
- if tex.color_mode == 'POSITION':
- texStrg+="solid\n"
- texStrg+="scale 0.25\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ if tex.type == "VORONOI":
+ text_strg += "crackle\n"
+ text_strg += " offset %.4g\n" % tex.nabla
+ text_strg += " form <%.4g,%.4g,%.4g>\n" % (tex.weight_1, tex.weight_2, tex.weight_3)
+ if tex.distance_metric == "DISTANCE":
+ text_strg += " metric 2.5\n"
+ if tex.distance_metric == "DISTANCE_SQUARED":
+ text_strg += " metric 2.5\n"
+ text_strg += " poly_wave 2\n"
+ if tex.distance_metric == "MINKOVSKY":
+ text_strg += " metric %s\n" % tex.minkovsky_exponent
+ if tex.distance_metric == "MINKOVSKY_FOUR":
+ text_strg += " metric 4\n"
+ if tex.distance_metric == "MINKOVSKY_HALF":
+ text_strg += " metric 0.5\n"
+ if tex.distance_metric == "CHEBYCHEV":
+ text_strg += " metric 10\n"
+ if tex.distance_metric == "MANHATTAN":
+ text_strg += " metric 1\n"
+
+ if tex.color_mode == "POSITION":
+ text_strg += "solid\n"
+ text_strg += "scale 0.25\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<0,0,0,1>]\n"
- texStrg+="[1 color rgbt<1,1,1,0>]\n"
- texStrg+="}\n"
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<0,0,0,1>]\n"
+ text_strg += "[1 color rgbt<1,1,1,0>]\n"
+ text_strg += "}\n"
####################### EMULATE BLENDER CLOUDS TEXTURE ####################
- if tex.type == 'CLOUDS':
- if tex.noise_type == 'SOFT_NOISE':
- texStrg+="wrinkles\n"
- texStrg+="scale 0.25\n"
+ if tex.type == "CLOUDS":
+ if tex.noise_type == "SOFT_NOISE":
+ text_strg += "wrinkles\n"
+ text_strg += "scale 0.25\n"
else:
- texStrg+="granite\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ text_strg += "granite\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<0,0,0,1>]\n"
- texStrg+="[1 color rgbt<1,1,1,0>]\n"
- texStrg+="}\n"
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<0,0,0,1>]\n"
+ text_strg += "[1 color rgbt<1,1,1,0>]\n"
+ text_strg += "}\n"
####################### EMULATE BLENDER WOOD TEXTURE ####################
- if tex.type == 'WOOD':
- if tex.wood_type == 'RINGS':
- texStrg+="wood\n"
- texStrg+="scale 0.25\n"
- if tex.wood_type == 'RINGNOISE':
- texStrg+="wood\n"
- texStrg+="scale 0.25\n"
- texStrg+="turbulence %.4g\n"%(tex.turbulence/100)
- if tex.wood_type == 'BANDS':
- texStrg+="marble\n"
- texStrg+="scale 0.25\n"
- texStrg+="rotate <45,-45,45>\n"
- if tex.wood_type == 'BANDNOISE':
- texStrg+="marble\n"
- texStrg+="scale 0.25\n"
- texStrg+="rotate <45,-45,45>\n"
- texStrg+="turbulence %.4g\n"%(tex.turbulence/10)
-
- if tex.noise_basis_2 == 'SIN':
- texStrg+="sine_wave\n"
- if tex.noise_basis_2 == 'TRI':
- texStrg+="triangle_wave\n"
- if tex.noise_basis_2 == 'SAW':
- texStrg+="ramp_wave\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ if tex.type == "WOOD":
+ if tex.wood_type == "RINGS":
+ text_strg += "wood\n"
+ text_strg += "scale 0.25\n"
+ if tex.wood_type == "RINGNOISE":
+ text_strg += "wood\n"
+ text_strg += "scale 0.25\n"
+ text_strg += "turbulence %.4g\n" % (tex.turbulence / 100)
+ if tex.wood_type == "BANDS":
+ text_strg += "marble\n"
+ text_strg += "scale 0.25\n"
+ text_strg += "rotate <45,-45,45>\n"
+ if tex.wood_type == "BANDNOISE":
+ text_strg += "marble\n"
+ text_strg += "scale 0.25\n"
+ text_strg += "rotate <45,-45,45>\n"
+ text_strg += "turbulence %.4g\n" % (tex.turbulence / 10)
+
+ if tex.noise_basis_2 == "SIN":
+ text_strg += "sine_wave\n"
+ if tex.noise_basis_2 == "TRI":
+ text_strg += "triangle_wave\n"
+ if tex.noise_basis_2 == "SAW":
+ text_strg += "ramp_wave\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<0,0,0,0>]\n"
- texStrg+="[1 color rgbt<1,1,1,0>]\n"
- texStrg+="}\n"
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<0,0,0,0>]\n"
+ text_strg += "[1 color rgbt<1,1,1,0>]\n"
+ text_strg += "}\n"
####################### EMULATE BLENDER STUCCI TEXTURE ####################
- if tex.type == 'STUCCI':
- texStrg+="bozo\n"
- texStrg+="scale 0.25\n"
- if tex.noise_type == 'HARD_NOISE':
- texStrg+="triangle_wave\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ if tex.type == "STUCCI":
+ text_strg += "bozo\n"
+ text_strg += "scale 0.25\n"
+ if tex.noise_type == "HARD_NOISE":
+ text_strg += "triangle_wave\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbf<1,1,1,0>]\n"
- texStrg+="[1 color rgbt<0,0,0,1>]\n"
- texStrg+="}\n"
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbf<1,1,1,0>]\n"
+ text_strg += "[1 color rgbt<0,0,0,1>]\n"
+ text_strg += "}\n"
else:
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbf<0,0,0,1>]\n"
- texStrg+="[1 color rgbt<1,1,1,0>]\n"
- texStrg+="}\n"
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbf<0,0,0,1>]\n"
+ text_strg += "[1 color rgbt<1,1,1,0>]\n"
+ text_strg += "}\n"
####################### EMULATE BLENDER MAGIC TEXTURE ####################
- if tex.type == 'MAGIC':
- texStrg+="leopard\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ if tex.type == "MAGIC":
+ text_strg += "leopard\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<1,1,1,0.5>]\n"
- texStrg+="[0.25 color rgbf<0,1,0,0.75>]\n"
- texStrg+="[0.5 color rgbf<0,0,1,0.75>]\n"
- texStrg+="[0.75 color rgbf<1,0,1,0.75>]\n"
- texStrg+="[1 color rgbf<0,1,0,0.75>]\n"
- texStrg+="}\n"
- texStrg+="scale 0.1\n"
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<1,1,1,0.5>]\n"
+ text_strg += "[0.25 color rgbf<0,1,0,0.75>]\n"
+ text_strg += "[0.5 color rgbf<0,0,1,0.75>]\n"
+ text_strg += "[0.75 color rgbf<1,0,1,0.75>]\n"
+ text_strg += "[1 color rgbf<0,1,0,0.75>]\n"
+ text_strg += "}\n"
+ text_strg += "scale 0.1\n"
####################### EMULATE BLENDER MARBLE TEXTURE ####################
- if tex.type == 'MARBLE':
- texStrg+="marble\n"
- texStrg+="turbulence 0.5\n"
- texStrg+="noise_generator 3\n"
- texStrg+="scale 0.75\n"
- texStrg+="rotate <45,-45,45>\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ if tex.type == "MARBLE":
+ text_strg += "marble\n"
+ text_strg += "turbulence 0.5\n"
+ text_strg += "noise_generator 3\n"
+ text_strg += "scale 0.75\n"
+ text_strg += "rotate <45,-45,45>\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- if tex.marble_type == 'SOFT':
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<0,0,0,0>]\n"
- texStrg+="[0.05 color rgbt<0,0,0,0>]\n"
- texStrg+="[1 color rgbt<0.9,0.9,0.9,0>]\n"
- texStrg+="}\n"
- elif tex.marble_type == 'SHARP':
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<0,0,0,0>]\n"
- texStrg+="[0.025 color rgbt<0,0,0,0>]\n"
- texStrg+="[1 color rgbt<0.9,0.9,0.9,0>]\n"
- texStrg+="}\n"
+ if tex.marble_type == "SOFT":
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<0,0,0,0>]\n"
+ text_strg += "[0.05 color rgbt<0,0,0,0>]\n"
+ text_strg += "[1 color rgbt<0.9,0.9,0.9,0>]\n"
+ text_strg += "}\n"
+ elif tex.marble_type == "SHARP":
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<0,0,0,0>]\n"
+ text_strg += "[0.025 color rgbt<0,0,0,0>]\n"
+ text_strg += "[1 color rgbt<0.9,0.9,0.9,0>]\n"
+ text_strg += "}\n"
else:
- texStrg+="[0 color rgbt<0,0,0,0>]\n"
- texStrg+="[1 color rgbt<1,1,1,0>]\n"
- texStrg+="}\n"
- if tex.noise_basis_2 == 'SIN':
- texStrg+="sine_wave\n"
- if tex.noise_basis_2 == 'TRI':
- texStrg+="triangle_wave\n"
- if tex.noise_basis_2 == 'SAW':
- texStrg+="ramp_wave\n"
+ text_strg += "[0 color rgbt<0,0,0,0>]\n"
+ text_strg += "[1 color rgbt<1,1,1,0>]\n"
+ text_strg += "}\n"
+ if tex.noise_basis_2 == "SIN":
+ text_strg += "sine_wave\n"
+ if tex.noise_basis_2 == "TRI":
+ text_strg += "triangle_wave\n"
+ if tex.noise_basis_2 == "SAW":
+ text_strg += "ramp_wave\n"
####################### EMULATE BLENDER BLEND TEXTURE ####################
- if tex.type == 'BLEND':
- if tex.progression=='RADIAL':
- texStrg+="radial\n"
- if tex.use_flip_axis=='HORIZONTAL':
- texStrg+="rotate x*90\n"
+ if tex.type == "BLEND":
+ if tex.progression == "RADIAL":
+ text_strg += "radial\n"
+ if tex.use_flip_axis == "HORIZONTAL":
+ text_strg += "rotate x*90\n"
else:
- texStrg+="rotate <-90,0,90>\n"
- texStrg+="ramp_wave\n"
- elif tex.progression=='SPHERICAL':
- texStrg+="spherical\n"
- texStrg+="scale 3\n"
- texStrg+="poly_wave 1\n"
- elif tex.progression=='QUADRATIC_SPHERE':
- texStrg+="spherical\n"
- texStrg+="scale 3\n"
- texStrg+=" poly_wave 2\n"
- elif tex.progression=='DIAGONAL':
- texStrg+="gradient <1,1,0>\n"
- texStrg+="scale 3\n"
- elif tex.use_flip_axis=='HORIZONTAL':
- texStrg+="gradient x\n"
- texStrg+="scale 2.01\n"
- elif tex.use_flip_axis=='VERTICAL':
- texStrg+="gradient y\n"
- texStrg+="scale 2.01\n"
- #texStrg+="ramp_wave\n"
- #texStrg+="frequency 0.5\n"
- texStrg+="phase 0.5\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ text_strg += "rotate <-90,0,90>\n"
+ text_strg += "ramp_wave\n"
+ elif tex.progression == "SPHERICAL":
+ text_strg += "spherical\n"
+ text_strg += "scale 3\n"
+ text_strg += "poly_wave 1\n"
+ elif tex.progression == "QUADRATIC_SPHERE":
+ text_strg += "spherical\n"
+ text_strg += "scale 3\n"
+ text_strg += " poly_wave 2\n"
+ elif tex.progression == "DIAGONAL":
+ text_strg += "gradient <1,1,0>\n"
+ text_strg += "scale 3\n"
+ elif tex.use_flip_axis == "HORIZONTAL":
+ text_strg += "gradient x\n"
+ text_strg += "scale 2.01\n"
+ elif tex.use_flip_axis == "VERTICAL":
+ text_strg += "gradient y\n"
+ text_strg += "scale 2.01\n"
+ # text_strg+="ramp_wave\n"
+ # text_strg+="frequency 0.5\n"
+ text_strg += "phase 0.5\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<1,1,1,0>]\n"
- texStrg+="[1 color rgbf<0,0,0,1>]\n"
- texStrg+="}\n"
- if tex.progression == 'LINEAR':
- texStrg+=" poly_wave 1\n"
- if tex.progression == 'QUADRATIC':
- texStrg+=" poly_wave 2\n"
- if tex.progression == 'EASING':
- texStrg+=" poly_wave 1.5\n"
-
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<1,1,1,0>]\n"
+ text_strg += "[1 color rgbf<0,0,0,1>]\n"
+ text_strg += "}\n"
+ if tex.progression == "LINEAR":
+ text_strg += " poly_wave 1\n"
+ if tex.progression == "QUADRATIC":
+ text_strg += " poly_wave 2\n"
+ if tex.progression == "EASING":
+ text_strg += " poly_wave 1.5\n"
####################### EMULATE BLENDER MUSGRAVE TEXTURE ####################
# if tex.type == 'MUSGRAVE':
- # texStrg+="function{ f_ridged_mf( x, y, 0, 1, 2, 9, -0.5, 3,3 )*0.5}\n"
- # texStrg+="color_map {\n"
- # texStrg+="[0 color rgbf<0,0,0,1>]\n"
- # texStrg+="[1 color rgbf<1,1,1,0>]\n"
- # texStrg+="}\n"
+ # text_strg+="function{ f_ridged_mf( x, y, 0, 1, 2, 9, -0.5, 3,3 )*0.5}\n"
+ # text_strg+="color_map {\n"
+ # text_strg+="[0 color rgbf<0,0,0,1>]\n"
+ # text_strg+="[1 color rgbf<1,1,1,0>]\n"
+ # text_strg+="}\n"
# simplified for now:
- if tex.type == 'MUSGRAVE':
- texStrg+="bozo scale 0.25 \n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ if tex.type == "MUSGRAVE":
+ text_strg += "bozo scale 0.25 \n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {[0.5 color rgbf<0,0,0,1>][1 color rgbt<1,1,1,0>]}ramp_wave \n"
+ text_strg += (
+ "color_map {[0.5 color rgbf<0,0,0,1>][1 color rgbt<1,1,1,0>]}ramp_wave \n"
+ )
####################### EMULATE BLENDER DISTORTED NOISE TEXTURE ####################
- if tex.type == 'DISTORTED_NOISE':
- texStrg+="average\n"
- texStrg+=" pigment_map {\n"
- texStrg+=" [1 bozo scale 0.25 turbulence %.4g\n" %tex.distortion
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ if tex.type == "DISTORTED_NOISE":
+ text_strg += "average\n"
+ text_strg += " pigment_map {\n"
+ text_strg += " [1 bozo scale 0.25 turbulence %.4g\n" % tex.distortion
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<1,1,1,0>]\n"
- texStrg+="[1 color rgbf<0,0,0,1>]\n"
- texStrg+="}\n"
- texStrg+="]\n"
-
- if tex.noise_distortion == 'CELL_NOISE':
- texStrg+=" [1 cells scale 0.1\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<1,1,1,0>]\n"
+ text_strg += "[1 color rgbf<0,0,0,1>]\n"
+ text_strg += "}\n"
+ text_strg += "]\n"
+
+ if tex.noise_distortion == "CELL_NOISE":
+ text_strg += " [1 cells scale 0.1\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<1,1,1,0>]\n"
- texStrg+="[1 color rgbf<0,0,0,1>]\n"
- texStrg+="}\n"
- texStrg+="]\n"
- if tex.noise_distortion=='VORONOI_CRACKLE':
- texStrg+=" [1 crackle scale 0.25\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<1,1,1,0>]\n"
+ text_strg += "[1 color rgbf<0,0,0,1>]\n"
+ text_strg += "}\n"
+ text_strg += "]\n"
+ if tex.noise_distortion == "VORONOI_CRACKLE":
+ text_strg += " [1 crackle scale 0.25\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<1,1,1,0>]\n"
- texStrg+="[1 color rgbf<0,0,0,1>]\n"
- texStrg+="}\n"
- texStrg+="]\n"
- if tex.noise_distortion in ['VORONOI_F1','VORONOI_F2','VORONOI_F3','VORONOI_F4','VORONOI_F2_F1']:
- texStrg+=" [1 crackle metric 2.5 scale 0.25 turbulence %.4g\n" %(tex.distortion/2)
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<1,1,1,0>]\n"
+ text_strg += "[1 color rgbf<0,0,0,1>]\n"
+ text_strg += "}\n"
+ text_strg += "]\n"
+ if tex.noise_distortion in [
+ "VORONOI_F1",
+ "VORONOI_F2",
+ "VORONOI_F3",
+ "VORONOI_F4",
+ "VORONOI_F2_F1",
+ ]:
+ text_strg += " [1 crackle metric 2.5 scale 0.25 turbulence %.4g\n" % (
+ tex.distortion / 2
+ )
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<1,1,1,0>]\n"
- texStrg+="[1 color rgbf<0,0,0,1>]\n"
- texStrg+="}\n"
- texStrg+="]\n"
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<1,1,1,0>]\n"
+ text_strg += "[1 color rgbf<0,0,0,1>]\n"
+ text_strg += "}\n"
+ text_strg += "]\n"
else:
- texStrg+=" [1 wrinkles scale 0.25\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ text_strg += " [1 wrinkles scale 0.25\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0 color rgbt<1,1,1,0>]\n"
- texStrg+="[1 color rgbf<0,0,0,1>]\n"
- texStrg+="}\n"
- texStrg+="]\n"
- texStrg+=" }\n"
+ text_strg += "color_map {\n"
+ text_strg += "[0 color rgbt<1,1,1,0>]\n"
+ text_strg += "[1 color rgbf<0,0,0,1>]\n"
+ text_strg += "}\n"
+ text_strg += "]\n"
+ text_strg += " }\n"
####################### EMULATE BLENDER NOISE TEXTURE ####################
- if tex.type == 'NOISE':
- texStrg+="cells\n"
- texStrg+="turbulence 3\n"
- texStrg+="omega 3\n"
- if tex.use_color_ramp == True:
- texStrg+=exportColorRamp(tex)
+ if tex.type == "NOISE":
+ text_strg += "cells\n"
+ text_strg += "turbulence 3\n"
+ text_strg += "omega 3\n"
+ if tex.use_color_ramp:
+ text_strg += export_color_ramp(tex)
else:
- texStrg+="color_map {\n"
- texStrg+="[0.75 color rgb<0,0,0,>]\n"
- texStrg+="[1 color rgb<1,1,1,>]\n"
- texStrg+="}\n"
+ text_strg += "color_map {\n"
+ text_strg += "[0.75 color rgb<0,0,0,>]\n"
+ text_strg += "[1 color rgb<1,1,1,>]\n"
+ text_strg += "}\n"
####################### IGNORE OTHER BLENDER TEXTURE ####################
- else: #non translated textures
+ else: # non translated textures
pass
- texStrg+="}\n\n"
-
- texStrg+="#declare f%s=\n"%PATname
- texStrg+="function{pigment{%s}}\n"%PATname
- texStrg+="\n"
-
- elif pat.tex_pattern_type != 'emulator':
- texStrg+="pigment {\n"
- texStrg+="%s\n"%pat.tex_pattern_type
- if pat.tex_pattern_type == 'agate':
- texStrg+="agate_turb %.4g\n"%pat.modifier_turbulence
- if pat.tex_pattern_type in {'spiral1', 'spiral2', 'tiling'}:
- texStrg+="%s\n"%pat.modifier_numbers
- if pat.tex_pattern_type == 'quilted':
- texStrg+="control0 %s control1 %s\n"%(pat.modifier_control0, pat.modifier_control1)
- if pat.tex_pattern_type == 'mandel':
- texStrg+="%s exponent %s \n"%(pat.f_iter, pat.f_exponent)
- if pat.tex_pattern_type == 'julia':
- texStrg+="<%.4g, %.4g> %s exponent %s \n"%(pat.julia_complex_1, pat.julia_complex_2, pat.f_iter, pat.f_exponent)
- if pat.tex_pattern_type == 'magnet' and pat.magnet_style == 'mandel':
- texStrg+="%s mandel %s \n"%(pat.magnet_type, pat.f_iter)
- if pat.tex_pattern_type == 'magnet' and pat.magnet_style == 'julia':
- texStrg+="%s julia <%.4g, %.4g> %s\n"%(pat.magnet_type, pat.julia_complex_1, pat.julia_complex_2, pat.f_iter)
- if pat.tex_pattern_type in {'mandel', 'julia', 'magnet'}:
- texStrg+="interior %s, %.4g\n"%(pat.f_ior, pat.f_ior_fac)
- texStrg+="exterior %s, %.4g\n"%(pat.f_eor, pat.f_eor_fac)
- if pat.tex_pattern_type == 'gradient':
- texStrg+="<%s, %s, %s> \n"%(pat.grad_orient_x, pat.grad_orient_y, pat.grad_orient_z)
- if pat.tex_pattern_type == 'pavement':
- numTiles=pat.pave_tiles
- numPattern=1
- if pat.pave_sides == '4' and pat.pave_tiles == 3:
- numPattern = pat.pave_pat_2
- if pat.pave_sides == '6' and pat.pave_tiles == 3:
- numPattern = pat.pave_pat_3
- if pat.pave_sides == '3' and pat.pave_tiles == 4:
- numPattern = pat.pave_pat_3
- if pat.pave_sides == '3' and pat.pave_tiles == 5:
- numPattern = pat.pave_pat_4
- if pat.pave_sides == '4' and pat.pave_tiles == 4:
- numPattern = pat.pave_pat_5
- if pat.pave_sides == '6' and pat.pave_tiles == 4:
- numPattern = pat.pave_pat_7
- if pat.pave_sides == '4' and pat.pave_tiles == 5:
- numPattern = pat.pave_pat_12
- if pat.pave_sides == '3' and pat.pave_tiles == 6:
- numPattern = pat.pave_pat_12
- if pat.pave_sides == '6' and pat.pave_tiles == 5:
- numPattern = pat.pave_pat_22
- if pat.pave_sides == '4' and pat.pave_tiles == 6:
- numPattern = pat.pave_pat_35
- if pat.pave_sides == '6' and pat.pave_tiles == 6:
- numTiles = 5
- texStrg+="number_of_sides %s number_of_tiles %s pattern %s form %s \n"%(pat.pave_sides, numTiles, numPattern, pat.pave_form)
- ################ functions #####################################################################################################
- if pat.tex_pattern_type == 'function':
- texStrg+="{ %s"%pat.func_list
- texStrg+="(x"
+ text_strg += "}\n\n"
+
+ text_strg += "#declare f%s=\n" % pat_name
+ text_strg += "function{pigment{%s}}\n" % pat_name
+ text_strg += "\n"
+
+ elif pat.tex_pattern_type != "emulator":
+ text_strg += "pigment {\n"
+ text_strg += "%s\n" % pat.tex_pattern_type
+ if pat.tex_pattern_type == "agate":
+ text_strg += "agate_turb %.4g\n" % pat.modifier_turbulence
+ if pat.tex_pattern_type in {"spiral1", "spiral2", "tiling"}:
+ text_strg += "%s\n" % pat.modifier_numbers
+ if pat.tex_pattern_type == "quilted":
+ text_strg += "control0 %s control1 %s\n" % (
+ pat.modifier_control0,
+ pat.modifier_control1,
+ )
+ if pat.tex_pattern_type == "mandel":
+ text_strg += "%s exponent %s \n" % (pat.f_iter, pat.f_exponent)
+ if pat.tex_pattern_type == "julia":
+ text_strg += "<%.4g, %.4g> %s exponent %s \n" % (
+ pat.julia_complex_1,
+ pat.julia_complex_2,
+ pat.f_iter,
+ pat.f_exponent,
+ )
+ if pat.tex_pattern_type == "magnet" and pat.magnet_style == "mandel":
+ text_strg += "%s mandel %s \n" % (pat.magnet_type, pat.f_iter)
+ if pat.tex_pattern_type == "magnet" and pat.magnet_style == "julia":
+ text_strg += "%s julia <%.4g, %.4g> %s\n" % (
+ pat.magnet_type,
+ pat.julia_complex_1,
+ pat.julia_complex_2,
+ pat.f_iter,
+ )
+ if pat.tex_pattern_type in {"mandel", "julia", "magnet"}:
+ text_strg += "interior %s, %.4g\n" % (pat.f_ior, pat.f_ior_fac)
+ text_strg += "exterior %s, %.4g\n" % (pat.f_eor, pat.f_eor_fac)
+ if pat.tex_pattern_type == "gradient":
+ text_strg += "<%s, %s, %s> \n" % (
+ pat.grad_orient_x,
+ pat.grad_orient_y,
+ pat.grad_orient_z,
+ )
+ if pat.tex_pattern_type == "pavement":
+ num_tiles = pat.pave_tiles
+ num_pattern = 1
+ if pat.pave_sides == "4" and pat.pave_tiles == 3:
+ num_pattern = pat.pave_pat_2
+ if pat.pave_sides == "6" and pat.pave_tiles == 3:
+ num_pattern = pat.pave_pat_3
+ if pat.pave_sides == "3" and pat.pave_tiles == 4:
+ num_pattern = pat.pave_pat_3
+ if pat.pave_sides == "3" and pat.pave_tiles == 5:
+ num_pattern = pat.pave_pat_4
+ if pat.pave_sides == "4" and pat.pave_tiles == 4:
+ num_pattern = pat.pave_pat_5
+ if pat.pave_sides == "6" and pat.pave_tiles == 4:
+ num_pattern = pat.pave_pat_7
+ if pat.pave_sides == "4" and pat.pave_tiles == 5:
+ num_pattern = pat.pave_pat_12
+ if pat.pave_sides == "3" and pat.pave_tiles == 6:
+ num_pattern = pat.pave_pat_12
+ if pat.pave_sides == "6" and pat.pave_tiles == 5:
+ num_pattern = pat.pave_pat_22
+ if pat.pave_sides == "4" and pat.pave_tiles == 6:
+ num_pattern = pat.pave_pat_35
+ if pat.pave_sides == "6" and pat.pave_tiles == 6:
+ num_tiles = 5
+ text_strg += "number_of_sides %s number_of_tiles %s pattern %s form %s \n" % (
+ pat.pave_sides,
+ num_tiles,
+ num_pattern,
+ pat.pave_form,
+ )
+ ################ functions ##########################################################
+ if pat.tex_pattern_type == "function":
+ text_strg += "{ %s" % pat.func_list
+ text_strg += "(x"
if pat.func_plus_x != "NONE":
- if pat.func_plus_x =='increase':
- texStrg+="*"
- if pat.func_plus_x =='plus':
- texStrg+="+"
- texStrg+="%.4g"%pat.func_x
- texStrg+=",y"
+ if pat.func_plus_x == "increase":
+ text_strg += "*"
+ if pat.func_plus_x == "plus":
+ text_strg += "+"
+ text_strg += "%.4g" % pat.func_x
+ text_strg += ",y"
if pat.func_plus_y != "NONE":
- if pat.func_plus_y =='increase':
- texStrg+="*"
- if pat.func_plus_y =='plus':
- texStrg+="+"
- texStrg+="%.4g"%pat.func_y
- texStrg+=",z"
+ if pat.func_plus_y == "increase":
+ text_strg += "*"
+ if pat.func_plus_y == "plus":
+ text_strg += "+"
+ text_strg += "%.4g" % pat.func_y
+ text_strg += ",z"
if pat.func_plus_z != "NONE":
- if pat.func_plus_z =='increase':
- texStrg+="*"
- if pat.func_plus_z =='plus':
- texStrg+="+"
- texStrg+="%.4g"%pat.func_z
+ if pat.func_plus_z == "increase":
+ text_strg += "*"
+ if pat.func_plus_z == "plus":
+ text_strg += "+"
+ text_strg += "%.4g" % pat.func_z
sort = -1
- if pat.func_list in {"f_comma","f_crossed_trough","f_cubic_saddle","f_cushion","f_devils_curve",
- "f_enneper","f_glob","f_heart","f_hex_x","f_hex_y","f_hunt_surface",
- "f_klein_bottle","f_kummer_surface_v1","f_lemniscate_of_gerono","f_mitre",
- "f_nodal_cubic","f_noise_generator","f_odd","f_paraboloid","f_pillow",
- "f_piriform","f_quantum","f_quartic_paraboloid","f_quartic_saddle",
- "f_sphere","f_steiners_roman","f_torus_gumdrop","f_umbrella"}:
+ if pat.func_list in {
+ "f_comma",
+ "f_crossed_trough",
+ "f_cubic_saddle",
+ "f_cushion",
+ "f_devils_curve",
+ "f_enneper",
+ "f_glob",
+ "f_heart",
+ "f_hex_x",
+ "f_hex_y",
+ "f_hunt_surface",
+ "f_klein_bottle",
+ "f_kummer_surface_v1",
+ "f_lemniscate_of_gerono",
+ "f_mitre",
+ "f_nodal_cubic",
+ "f_noise_generator",
+ "f_odd",
+ "f_paraboloid",
+ "f_pillow",
+ "f_piriform",
+ "f_quantum",
+ "f_quartic_paraboloid",
+ "f_quartic_saddle",
+ "f_sphere",
+ "f_steiners_roman",
+ "f_torus_gumdrop",
+ "f_umbrella",
+ }:
sort = 0
- if pat.func_list in {"f_bicorn","f_bifolia","f_boy_surface","f_superellipsoid","f_torus"}:
+ if pat.func_list in {
+ "f_bicorn",
+ "f_bifolia",
+ "f_boy_surface",
+ "f_superellipsoid",
+ "f_torus",
+ }:
sort = 1
- if pat.func_list in {"f_ellipsoid","f_folium_surface","f_hyperbolic_torus",
- "f_kampyle_of_eudoxus","f_parabolic_torus","f_quartic_cylinder","f_torus2"}:
+ if pat.func_list in {
+ "f_ellipsoid",
+ "f_folium_surface",
+ "f_hyperbolic_torus",
+ "f_kampyle_of_eudoxus",
+ "f_parabolic_torus",
+ "f_quartic_cylinder",
+ "f_torus2",
+ }:
sort = 2
- if pat.func_list in {"f_blob2","f_cross_ellipsoids","f_flange_cover","f_isect_ellipsoids",
- "f_kummer_surface_v2","f_ovals_of_cassini","f_rounded_box","f_spikes_2d","f_strophoid"}:
+ if pat.func_list in {
+ "f_blob2",
+ "f_cross_ellipsoids",
+ "f_flange_cover",
+ "f_isect_ellipsoids",
+ "f_kummer_surface_v2",
+ "f_ovals_of_cassini",
+ "f_rounded_box",
+ "f_spikes_2d",
+ "f_strophoid",
+ }:
sort = 3
- if pat.func_list in {"f_algbr_cyl1","f_algbr_cyl2","f_algbr_cyl3","f_algbr_cyl4","f_blob","f_mesh1","f_poly4","f_spikes"}:
+ if pat.func_list in {
+ "f_algbr_cyl1",
+ "f_algbr_cyl2",
+ "f_algbr_cyl3",
+ "f_algbr_cyl4",
+ "f_blob",
+ "f_mesh1",
+ "f_poly4",
+ "f_spikes",
+ }:
sort = 4
- if pat.func_list in {"f_devils_curve_2d","f_dupin_cyclid","f_folium_surface_2d","f_hetero_mf","f_kampyle_of_eudoxus_2d",
- "f_lemniscate_of_gerono_2d","f_polytubes","f_ridge","f_ridged_mf","f_spiral","f_witch_of_agnesi"}:
+ if pat.func_list in {
+ "f_devils_curve_2d",
+ "f_dupin_cyclid",
+ "f_folium_surface_2d",
+ "f_hetero_mf",
+ "f_kampyle_of_eudoxus_2d",
+ "f_lemniscate_of_gerono_2d",
+ "f_polytubes",
+ "f_ridge",
+ "f_ridged_mf",
+ "f_spiral",
+ "f_witch_of_agnesi",
+ }:
sort = 5
- if pat.func_list in {"f_helix1","f_helix2","f_piriform_2d","f_strophoid_2d"}:
+ if pat.func_list in {"f_helix1", "f_helix2", "f_piriform_2d", "f_strophoid_2d"}:
sort = 6
if pat.func_list == "f_helical_torus":
sort = 7
if sort > -1:
- texStrg+=",%.4g"%pat.func_P0
+ text_strg += ",%.4g" % pat.func_P0
if sort > 0:
- texStrg+=",%.4g"%pat.func_P1
+ text_strg += ",%.4g" % pat.func_P1
if sort > 1:
- texStrg+=",%.4g"%pat.func_P2
+ text_strg += ",%.4g" % pat.func_P2
if sort > 2:
- texStrg+=",%.4g"%pat.func_P3
+ text_strg += ",%.4g" % pat.func_P3
if sort > 3:
- texStrg+=",%.4g"%pat.func_P4
+ text_strg += ",%.4g" % pat.func_P4
if sort > 4:
- texStrg+=",%.4g"%pat.func_P5
+ text_strg += ",%.4g" % pat.func_P5
if sort > 5:
- texStrg+=",%.4g"%pat.func_P6
+ text_strg += ",%.4g" % pat.func_P6
if sort > 6:
- texStrg+=",%.4g"%pat.func_P7
- texStrg+=",%.4g"%pat.func_P8
- texStrg+=",%.4g"%pat.func_P9
- texStrg+=")}\n"
+ text_strg += ",%.4g" % pat.func_P7
+ text_strg += ",%.4g" % pat.func_P8
+ text_strg += ",%.4g" % pat.func_P9
+ text_strg += ")}\n"
############## end functions ###############################################################
- if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
- texStrg+="color_map {\n"
- numColor=0
- if tex.use_color_ramp == True:
+ if pat.tex_pattern_type not in {"checker", "hexagon", "square", "triangular", "brick"}:
+ text_strg += "color_map {\n"
+ num_color = 0
+ if tex.use_color_ramp:
for el in tex.color_ramp.elements:
- numColor+=1
+ num_color += 1
pos = el.position
- col=el.color
- colR,colG,colB,colA = col[0],col[1],col[2],1-col[3]
- if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
- texStrg+="[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n"%(pos,colR,colG,colB,colA)
- if pat.tex_pattern_type in {'brick','checker'} and numColor < 3:
- texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
- if pat.tex_pattern_type == 'hexagon' and numColor < 4 :
- texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
- if pat.tex_pattern_type == 'square' and numColor < 5 :
- texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
- if pat.tex_pattern_type == 'triangular' and numColor < 7 :
- texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
+ col = el.color
+ col_r, col_g, col_b, col_a = col[0], col[1], col[2], 1 - col[3]
+ if pat.tex_pattern_type not in {
+ "checker",
+ "hexagon",
+ "square",
+ "triangular",
+ "brick",
+ }:
+ text_strg += "[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n" % (
+ pos,
+ col_r,
+ col_g,
+ col_b,
+ col_a,
+ )
+ if pat.tex_pattern_type in {"brick", "checker"} and num_color < 3:
+ text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+ if pat.tex_pattern_type == "hexagon" and num_color < 4:
+ text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+ if pat.tex_pattern_type == "square" and num_color < 5:
+ text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
+ if pat.tex_pattern_type == "triangular" and num_color < 7:
+ text_strg += "color rgbf<%.4g,%.4g,%.4g,%.4g> \n" % (col_r, col_g, col_b, col_a)
else:
- texStrg+="[0 color rgbf<0,0,0,1>]\n"
- texStrg+="[1 color rgbf<1,1,1,0>]\n"
- if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
- texStrg+="} \n"
- if pat.tex_pattern_type == 'brick':
- texStrg+="brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"%(pat.brick_size_x, pat.brick_size_y, pat.brick_size_z, pat.brick_mortar)
- texStrg+="%s \n"%mappingDif
- texStrg+="rotate <%.4g,%.4g,%.4g> \n"%(pat.tex_rot_x, pat.tex_rot_y, pat.tex_rot_z)
- texStrg+="turbulence <%.4g,%.4g,%.4g> \n"%(pat.warp_turbulence_x, pat.warp_turbulence_y, pat.warp_turbulence_z)
- texStrg+="octaves %s \n"%pat.modifier_octaves
- texStrg+="lambda %.4g \n"%pat.modifier_lambda
- texStrg+="omega %.4g \n"%pat.modifier_omega
- texStrg+="frequency %.4g \n"%pat.modifier_frequency
- texStrg+="phase %.4g \n"%pat.modifier_phase
- texStrg+="}\n\n"
- texStrg+="#declare f%s=\n"%PATname
- texStrg+="function{pigment{%s}}\n"%PATname
- texStrg+="\n"
- return(texStrg)
-
-
-def writeTextureInfluence(using_uberpov, mater, materialNames, LocalMaterialNames, path_image, lampCount,
- imageFormat, imgMap, imgMapTransforms, tabWrite, comments,
- string_strip_hyphen, safety, col, os, preview_dir, unpacked_images):
- """Translate Blender texture influences to various POV texture tricks and write to pov file."""
-
- material_finish = materialNames[mater.name]
- if mater.pov.use_transparency:
- trans = 1.0 - mater.pov.alpha
- else:
- trans = 0.0
- if ((mater.pov.specular_color.s == 0.0) or (mater.pov.diffuse_shader == 'MINNAERT')):
- # No layered texture because of aoi pattern used for minnaert and pov can't layer patterned
- colored_specular_found = False
- else:
- colored_specular_found = True
-
- if mater.pov.use_transparency and mater.pov.transparency_method == 'RAYTRACE':
- povFilter = mater.pov_raytrace_transparency.filter * (1.0 - mater.pov.alpha)
- trans = (1.0 - mater.pov.alpha) - povFilter
- else:
- povFilter = 0.0
-
- ##############SF
- texturesDif = ""
- texturesSpec = ""
- texturesNorm = ""
- texturesAlpha = ""
- #proceduralFlag=False
- tmpidx = -1
- for t in mater.pov_texture_slots:
-
-
- tmpidx += 1
- # index = mater.pov.active_texture_index
- slot = mater.pov_texture_slots[tmpidx] # [index]
- povtex = slot.texture # slot.name
- tex = bpy.data.textures[povtex]
-
- if t and (t.use and (tex is not None)):
- # 'NONE' ('NONE' type texture is different from no texture covered above)
- if (tex.type == 'NONE' and tex.pov.tex_pattern_type == 'emulator'):
- continue # move to next slot
- # PROCEDURAL
- elif (tex.type != 'IMAGE' and tex.type != 'NONE'):
- proceduralFlag=True
- image_filename = "PAT_%s"%string_strip_hyphen(bpy.path.clean_name(tex.name))
- if image_filename:
- if t.use_map_color_diffuse:
- texturesDif = image_filename
- # colvalue = t.default_value # UNUSED
- t_dif = t
- if t_dif.texture.pov.tex_gamma_enable:
- imgGamma = (" gamma %.3g " % t_dif.texture.pov.tex_gamma_value)
- if t.use_map_specular or t.use_map_raymir:
- texturesSpec = image_filename
- # colvalue = t.default_value # UNUSED
- t_spec = t
- if t.use_map_normal:
- texturesNorm = image_filename
- # colvalue = t.normal_factor/10 # UNUSED
- #textNormName=tex.image.name + ".normal"
- #was the above used? --MR
- t_nor = t
- if t.use_map_alpha:
- texturesAlpha = image_filename
- # colvalue = t.alpha_factor * 10.0 # UNUSED
- #textDispName=tex.image.name + ".displ"
- #was the above used? --MR
- t_alpha = t
-
- # RASTER IMAGE
- elif (tex.type == 'IMAGE' and tex.image and tex.pov.tex_pattern_type == 'emulator'):
- proceduralFlag=False
- #PACKED
- if tex.image.packed_file:
- orig_image_filename=tex.image.filepath_raw
- unpackedfilename= os.path.join(preview_dir,("unpacked_img_"+(string_strip_hyphen(bpy.path.clean_name(tex.name)))))
- if not os.path.exists(unpackedfilename):
- # record which images that were newly copied and can be safely
- # cleaned up
- unpacked_images.append(unpackedfilename)
- tex.image.filepath_raw=unpackedfilename
- tex.image.save()
- image_filename = unpackedfilename.replace("\\","/")
- # .replace("\\","/") to get only forward slashes as it's what POV prefers,
- # even on windows
- tex.image.filepath_raw=orig_image_filename
- #FILE
- else:
- image_filename = path_image(tex.image)
- # IMAGE SEQUENCE BEGINS
- if image_filename:
- if bpy.data.images[tex.image.name].source == 'SEQUENCE':
- korvaa = "." + str(tex.image_user.frame_offset + 1).zfill(3) + "."
- image_filename = image_filename.replace(".001.", korvaa)
- print(" seq debug ")
- print(image_filename)
- # IMAGE SEQUENCE ENDS
- imgGamma = ""
- if image_filename:
- texdata = bpy.data.textures[t.texture]
- if t.use_map_color_diffuse:
- texturesDif = image_filename
- # colvalue = t.default_value # UNUSED
- t_dif = t
- print (texdata)
- if texdata.pov.tex_gamma_enable:
- imgGamma = (" gamma %.3g " % t_dif.texture.pov.tex_gamma_value)
- if t.use_map_specular or t.use_map_raymir:
- texturesSpec = image_filename
- # colvalue = t.default_value # UNUSED
- t_spec = t
- if t.use_map_normal:
- texturesNorm = image_filename
- # colvalue = t.normal_factor/10 # UNUSED
- #textNormName=tex.image.name + ".normal"
- #was the above used? --MR
- t_nor = t
- if t.use_map_alpha:
- texturesAlpha = image_filename
- # colvalue = t.alpha_factor * 10.0 # UNUSED
- #textDispName=tex.image.name + ".displ"
- #was the above used? --MR
- t_alpha = t
-
- ####################################################################################
-
-
- tabWrite("\n")
- # THIS AREA NEEDS TO LEAVE THE TEXTURE OPEN UNTIL ALL MAPS ARE WRITTEN DOWN.
- # --MR
- currentMatName = string_strip_hyphen(materialNames[mater.name])
- LocalMaterialNames.append(currentMatName)
- tabWrite("\n#declare MAT_%s = \ntexture{\n" % currentMatName)
- ################################################################################
-
- if mater.pov.replacement_text != "":
- tabWrite("%s\n" % mater.pov.replacement_text)
- #################################################################################
- # XXX TODO: replace by new POV MINNAERT rather than aoi
- if mater.pov.diffuse_shader == 'MINNAERT':
- tabWrite("\n")
- tabWrite("aoi\n")
- tabWrite("texture_map {\n")
- tabWrite("[%.3g finish {diffuse %.3g}]\n" % \
- (mater.darkness / 2.0, 2.0 - mater.darkness))
- tabWrite("[%.3g\n" % (1.0 - (mater.darkness / 2.0)))
-
- if mater.pov.diffuse_shader == 'FRESNEL':
- # For FRESNEL diffuse in POV, we'll layer slope patterned textures
- # with lamp vector as the slope vector and nest one slope per lamp
- # into each texture map's entry.
-
- c = 1
- while (c <= lampCount):
- tabWrite("slope { lampTarget%s }\n" % (c))
- tabWrite("texture_map {\n")
- # Diffuse Fresnel value and factor go up to five,
- # other kind of values needed: used the number 5 below to remap
- tabWrite("[%.3g finish {diffuse %.3g}]\n" % \
- ((5.0 - mater.diffuse_fresnel) / 5,
- (mater.diffuse_intensity *
- ((5.0 - mater.diffuse_fresnel_factor) / 5))))
- tabWrite("[%.3g\n" % ((mater.diffuse_fresnel_factor / 5) *
- (mater.diffuse_fresnel / 5.0)))
- c += 1
-
- # if shader is a 'FRESNEL' or 'MINNAERT': slope pigment pattern or aoi
- # and texture map above, the rest below as one of its entry
-
- if texturesSpec != "" or texturesAlpha != "":
- if texturesSpec != "":
- # tabWrite("\n")
- tabWrite("pigment_pattern {\n")
-
- mappingSpec =imgMapTransforms(t_spec)
- if texturesSpec and texturesSpec.startswith("PAT_"):
- tabWrite("function{f%s(x,y,z).grey}\n" %texturesSpec)
- tabWrite("%s\n" % mappingSpec)
- else:
-
- tabWrite("uv_mapping image_map{%s \"%s\" %s}\n" % \
- (imageFormat(texturesSpec), texturesSpec, imgMap(t_spec)))
- tabWrite("%s\n" % mappingSpec)
- tabWrite("}\n")
- tabWrite("texture_map {\n")
- tabWrite("[0 \n")
-
- if texturesDif == "":
- if texturesAlpha != "":
- tabWrite("\n")
+ text_strg += "[0 color rgbf<0,0,0,1>]\n"
+ text_strg += "[1 color rgbf<1,1,1,0>]\n"
+ if pat.tex_pattern_type not in {"checker", "hexagon", "square", "triangular", "brick"}:
+ text_strg += "} \n"
+ if pat.tex_pattern_type == "brick":
+ text_strg += "brick_size <%.4g, %.4g, %.4g> mortar %.4g \n" % (
+ pat.brick_size_x,
+ pat.brick_size_y,
+ pat.brick_size_z,
+ pat.brick_mortar,
+ )
+ text_strg += "%s \n" % mapping_dif
+ text_strg += "rotate <%.4g,%.4g,%.4g> \n" % (pat.tex_rot_x, pat.tex_rot_y, pat.tex_rot_z)
+ text_strg += "turbulence <%.4g,%.4g,%.4g> \n" % (
+ pat.warp_turbulence_x,
+ pat.warp_turbulence_y,
+ pat.warp_turbulence_z,
+ )
+ text_strg += "octaves %s \n" % pat.modifier_octaves
+ text_strg += "lambda %.4g \n" % pat.modifier_lambda
+ text_strg += "omega %.4g \n" % pat.modifier_omega
+ text_strg += "frequency %.4g \n" % pat.modifier_frequency
+ text_strg += "phase %.4g \n" % pat.modifier_phase
+ text_strg += "}\n\n"
+ text_strg += "#declare f%s=\n" % pat_name
+ text_strg += "function{pigment{%s}}\n" % pat_name
+ text_strg += "\n"
+ return text_strg
- mappingAlpha = imgMapTransforms(t_alpha)
-
- if texturesAlpha and texturesAlpha.startswith("PAT_"):
- tabWrite("function{f%s(x,y,z).transmit}%s\n" %(texturesAlpha, mappingAlpha))
- else:
-
- tabWrite("pigment {pigment_pattern {uv_mapping image_map" \
- "{%s \"%s\" %s}%s" % \
- (imageFormat(texturesAlpha), texturesAlpha,
- imgMap(t_alpha), mappingAlpha))
- tabWrite("}\n")
- tabWrite("pigment_map {\n")
- tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
- tabWrite("[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n" % \
- (col[0], col[1], col[2], povFilter, trans))
- tabWrite("}\n")
- tabWrite("}\n")
-
- else:
-
- tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n" % \
- (col[0], col[1], col[2], povFilter, trans))
-
- if texturesSpec != "":
- # Level 1 is no specular
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=1)))
-
- else:
- # Level 2 is translated spec
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
-
- else:
- mappingDif = imgMapTransforms(t_dif)
-
- if texturesAlpha != "":
- mappingAlpha = imgMapTransforms(t_alpha)
-
- tabWrite("pigment {\n")
- tabWrite("pigment_pattern {\n")
- if texturesAlpha and texturesAlpha.startswith("PAT_"):
- tabWrite("function{f%s(x,y,z).transmit}%s\n" %(texturesAlpha, mappingAlpha))
- else:
- tabWrite("uv_mapping image_map{%s \"%s\" %s}%s}\n" % \
- (imageFormat(texturesAlpha), texturesAlpha,
- imgMap(t_alpha), mappingAlpha))
- tabWrite("pigment_map {\n")
- tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
- #if texturesAlpha and texturesAlpha.startswith("PAT_"):
- #tabWrite("[1 pigment{%s}]\n" %texturesDif)
- if texturesDif and not texturesDif.startswith("PAT_"):
- tabWrite("[1 uv_mapping image_map {%s \"%s\" %s} %s]\n" % \
- (imageFormat(texturesDif), texturesDif,
- (imgGamma + imgMap(t_dif)), mappingDif))
- elif texturesDif and texturesDif.startswith("PAT_"):
- tabWrite("[1 %s]\n" %texturesDif)
- tabWrite("}\n")
- tabWrite("}\n")
- if texturesAlpha and texturesAlpha.startswith("PAT_"):
- tabWrite("}\n")
-
- else:
- if texturesDif and texturesDif.startswith("PAT_"):
- tabWrite("pigment{%s}\n" %texturesDif)
- else:
- tabWrite("pigment {uv_mapping image_map {%s \"%s\" %s}%s}\n" % \
- (imageFormat(texturesDif), texturesDif,
- (imgGamma + imgMap(t_dif)), mappingDif))
-
- if texturesSpec != "":
- # Level 1 is no specular
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=1)))
-
- else:
- # Level 2 is translated specular
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
-
- ## scale 1 rotate y*0
- #imageMap = ("{image_map {%s \"%s\" %s }\n" % \
- # (imageFormat(textures),textures,imgMap(t_dif)))
- #tabWrite("uv_mapping pigment %s} %s finish {%s}\n" % \
- # (imageMap,mapping,safety(material_finish)))
- #tabWrite("pigment {uv_mapping image_map {%s \"%s\" %s}%s} " \
- # "finish {%s}\n" % \
- # (imageFormat(texturesDif), texturesDif, imgMap(t_dif),
- # mappingDif, safety(material_finish)))
- if texturesNorm != "":
- ## scale 1 rotate y*0
-
- mappingNor =imgMapTransforms(t_nor)
-
- if texturesNorm and texturesNorm.startswith("PAT_"):
- tabWrite("normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n" %(texturesNorm, ( - t_nor.normal_factor * 9.5), mappingNor))
- else:
- tabWrite("normal {\n")
- # XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
- if (mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov):
- tabWrite("average\n")
- tabWrite("normal_map{\n")
- # 0.5 for entries below means a 50 percent mix
- # between the micro normal and user bump map
- # order seems indifferent as commutative
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(10/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[1.0 ") # Proceed with user bump...
- tabWrite("uv_mapping bump_map " \
- "{%s \"%s\" %s bump_size %.4g }%s" % \
- (imageFormat(texturesNorm), texturesNorm, imgMap(t_nor),
- ( - t_nor.normal_factor * 9.5), mappingNor))
- # ...Then close its last entry and the the normal_map itself
- if (mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov):
- tabWrite("]}}\n")
- else:
- tabWrite("]}\n")
- if texturesSpec != "":
- tabWrite("]\n")
- ##################Second index for mapping specular max value###############
- tabWrite("[1 \n")
-
- if texturesDif == "" and mater.pov.replacement_text == "":
- if texturesAlpha != "":
- mappingAlpha = imgMapTransforms(t_alpha)
-
- if texturesAlpha and texturesAlpha.startswith("PAT_"):
- tabWrite("function{f%s(x,y,z).transmit %s}\n" %(texturesAlpha, mappingAlpha))
- else:
- tabWrite("pigment {pigment_pattern {uv_mapping image_map" \
- "{%s \"%s\" %s}%s}\n" % \
- (imageFormat(texturesAlpha), texturesAlpha, imgMap(t_alpha),
- mappingAlpha))
- tabWrite("pigment_map {\n")
- tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
- tabWrite("[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n" % \
- (col[0], col[1], col[2], povFilter, trans))
- tabWrite("}\n")
- tabWrite("}\n")
-
- else:
- tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n" % \
- (col[0], col[1], col[2], povFilter, trans))
-
-
- if texturesSpec != "":
- # Level 3 is full specular
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=3)))
-
- if mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov:
- tabWrite("normal {\n")
- tabWrite("average\n")
- tabWrite("normal_map{\n")
- # 0.5 for entries below means a 50 percent mix
- # between the micro normal and user bump map
- # order seems indifferent as commutative
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(10/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- #XXX IF USER BUMP_MAP
- if texturesNorm != "":
- tabWrite("[1.0 ") # Blurry reflection or not Proceed with user bump in either case...
- tabWrite("uv_mapping bump_map " \
- "{%s \"%s\" %s bump_size %.4g }%s]\n" % \
- (imageFormat(texturesNorm), texturesNorm, imgMap(t_nor),
- ( - t_nor.normal_factor * 9.5), mappingNor))
- # ...Then close the normal_map itself if blurry reflection
- if mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov:
- tabWrite("}}\n")
- else:
- tabWrite("}\n")
- elif colored_specular_found:
- # Level 1 is no specular
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=1)))
-
- else:
- # Level 2 is translated specular
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
-
- elif mater.pov.replacement_text == "":
- mappingDif = imgMapTransforms(t_dif)
-
- if texturesAlpha != "":
-
- mappingAlpha = imgMapTransforms(t_alpha)
-
- if texturesAlpha and texturesAlpha.startswith("PAT_"):
- tabWrite("pigment{pigment_pattern {function{f%s(x,y,z).transmit}%s}\n" %(texturesAlpha, mappingAlpha))
- else:
- tabWrite("pigment {pigment_pattern {uv_mapping image_map" \
- "{%s \"%s\" %s}%s}\n" % \
- (imageFormat(texturesAlpha), texturesAlpha, imgMap(t_alpha),
- mappingAlpha))
- tabWrite("pigment_map {\n")
- tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
- if texturesAlpha and texturesAlpha.startswith("PAT_"):
- tabWrite("[1 function{f%s(x,y,z).transmit}%s]\n" %(texturesAlpha, mappingAlpha))
- elif texturesDif and not texturesDif.startswith("PAT_"):
- tabWrite("[1 uv_mapping image_map {%s \"%s\" %s} %s]\n" % \
- (imageFormat(texturesDif), texturesDif,
- (imgMap(t_dif) + imgGamma), mappingDif))
- elif texturesDif and texturesDif.startswith("PAT_"):
- tabWrite("[1 %s %s]\n" %(texturesDif, mappingDif))
- tabWrite("}\n")
- tabWrite("}\n")
-
- else:
- if texturesDif and texturesDif.startswith("PAT_"):
- tabWrite("pigment{%s %s}\n" %(texturesDif, mappingDif))
- else:
- tabWrite("pigment {\n")
- tabWrite("uv_mapping image_map {\n")
- #tabWrite("%s \"%s\" %s}%s\n" % \
- # (imageFormat(texturesDif), texturesDif,
- # (imgGamma + imgMap(t_dif)),mappingDif))
- tabWrite("%s \"%s\" \n" % (imageFormat(texturesDif), texturesDif))
- tabWrite("%s\n" % (imgGamma + imgMap(t_dif)))
- tabWrite("}\n")
- tabWrite("%s\n" % mappingDif)
- tabWrite("}\n")
-
- if texturesSpec != "":
- # Level 3 is full specular
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=3)))
- else:
- # Level 2 is translated specular
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
-
- ## scale 1 rotate y*0
- #imageMap = ("{image_map {%s \"%s\" %s }" % \
- # (imageFormat(textures), textures,imgMap(t_dif)))
- #tabWrite("\n\t\t\tuv_mapping pigment %s} %s finish {%s}" % \
- # (imageMap, mapping, safety(material_finish)))
- #tabWrite("\n\t\t\tpigment {uv_mapping image_map " \
- # "{%s \"%s\" %s}%s} finish {%s}" % \
- # (imageFormat(texturesDif), texturesDif,imgMap(t_dif),
- # mappingDif, safety(material_finish)))
- if texturesNorm != "" and mater.pov.replacement_text == "":
-
-
- mappingNor =imgMapTransforms(t_nor)
-
- if texturesNorm and texturesNorm.startswith("PAT_"):
- tabWrite("normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n" %(texturesNorm, ( - t_nor.normal_factor * 9.5), mappingNor))
- else:
- tabWrite("normal {\n")
- # XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
- if mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov:
- tabWrite("average\n")
- tabWrite("normal_map{\n")
- # 0.5 for entries below means a 50 percent mix
- # between the micro normal and user bump map
- # order seems indifferent as commutative
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(10/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n" %((10/(mater.pov_raytrace_mirror.gloss_factor+0.01)),(1/(mater.pov_raytrace_mirror.gloss_samples+0.001)))) # micronormals blurring
- tabWrite("[1.0 ") # Blurry reflection or not Proceed with user bump in either case...
- tabWrite("uv_mapping bump_map " \
- "{%s \"%s\" %s bump_size %.4g }%s]\n" % \
- (imageFormat(texturesNorm), texturesNorm, imgMap(t_nor),
- ( - t_nor.normal_factor * 9.5), mappingNor))
- # ...Then close the normal_map itself if blurry reflection
- if mater.pov_raytrace_mirror.use and mater.pov_raytrace_mirror.gloss_factor < 1.0 and not using_uberpov:
- tabWrite("}}\n")
- else:
- tabWrite("}\n")
- if texturesSpec != "" and mater.pov.replacement_text == "":
- tabWrite("]\n")
-
- tabWrite("}\n")
-
- #End of slope/ior texture_map
- if mater.pov.diffuse_shader == 'MINNAERT' and mater.pov.replacement_text == "":
- tabWrite("]\n")
- tabWrite("}\n")
- if mater.pov.diffuse_shader == 'FRESNEL' and mater.pov.replacement_text == "":
- c = 1
- while (c <= lampCount):
- tabWrite("]\n")
- tabWrite("}\n")
- c += 1
-
-
-
- # Close first layer of POV "texture" (Blender material)
- tabWrite("}\n")
-
- if ((mater.pov.specular_color.s > 0.0) and (mater.pov.diffuse_shader != 'MINNAERT')):
-
- colored_specular_found = True
- else:
- colored_specular_found = False
-
- # Write another layered texture using invisible diffuse and metallic trick
- # to emulate colored specular highlights
- special_texture_found = False
- tmpidx = -1
- for t in mater.pov_texture_slots:
- tmpidx += 1
- # index = mater.pov.active_texture_index
- slot = mater.pov_texture_slots[tmpidx] # [index]
- povtex = slot.texture # slot.name
- tex = bpy.data.textures[povtex]
- if(t and t.use and ((tex.type == 'IMAGE' and tex.image) or tex.type != 'IMAGE') and
- (t.use_map_specular or t.use_map_raymir)):
- # Specular mapped textures would conflict with colored specular
- # because POV can't layer over or under pigment patterned textures
- special_texture_found = True
-
- if colored_specular_found and not special_texture_found:
- if comments:
- tabWrite(" // colored highlights with a stransparent metallic layer\n")
- else:
- tabWrite("\n")
-
- tabWrite("texture {\n")
- tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, 0, 1>}\n" % \
- (mater.pov.specular_color[0], mater.pov.specular_color[1], mater.pov.specular_color[2]))
- tabWrite("finish {%s}\n" % (safety(material_finish, Level=2))) # Level 2 is translated spec
-
- texturesNorm = ""
- for t in mater.pov_texture_slots:
-
- if t and tex.pov.tex_pattern_type != 'emulator':
- proceduralFlag=True
- image_filename = string_strip_hyphen(bpy.path.clean_name(tex.name))
- if (t and tex.type == 'IMAGE' and
- t.use and tex.image and
- tex.pov.tex_pattern_type == 'emulator'):
- proceduralFlag=False
- image_filename = path_image(tex.image)
- imgGamma = ""
- if image_filename:
- if t.use_map_normal:
- texturesNorm = image_filename
- # colvalue = t.normal_factor/10 # UNUSED XXX *-9.5 !
- #textNormName=tex.image.name + ".normal"
- #was the above used? --MR
- t_nor = t
- if proceduralFlag:
- tabWrite("normal{function" \
- "{f%s(x,y,z).grey} bump_size %.4g}\n" % \
- (texturesNorm,
- ( - t_nor.normal_factor * 9.5)))
- else:
- tabWrite("normal {uv_mapping bump_map " \
- "{%s \"%s\" %s bump_size %.4g }%s}\n" % \
- (imageFormat(texturesNorm),
- texturesNorm, imgMap(t_nor),
- ( - t_nor.normal_factor * 9.5),
- mappingNor))
-
- tabWrite("}\n") # THEN IT CAN CLOSE LAST LAYER OF TEXTURE
def string_strip_hyphen(name):
+ """POV naming schemes like to conform to most restrictive charsets."""
return name.replace("-", "")
+
+
# WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-def write_nodes(scene,povMatName,ntree,file):
- """translate Blender node trees to pov and write them to file"""
- declareNodes=[]
- scene=bpy.context.scene
+def write_nodes(scene, pov_mat_name, ntree, file):
+ """Translate Blender node trees to pov and write them to file."""
+ # such function local inlined import are official guidelines
+ # of Blender Foundation to lighten addons footprint at startup
+ from os import path
+
+ declare_nodes = []
+ scene = bpy.context.scene
for node in ntree.nodes:
- povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+ pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayFinishNode" and node.outputs["Finish"].is_linked:
- file.write('#declare %s = finish {\n'%povNodeName)
- emission=node.inputs["Emission"].default_value
+ file.write("#declare %s = finish {\n" % pov_node_name)
+ emission = node.inputs["Emission"].default_value
if node.inputs["Emission"].is_linked:
pass
- file.write(' emission %.4g\n'%emission)
+ file.write(" emission %.4g\n" % emission)
for link in ntree.links:
if link.to_node == node:
- if link.from_node.bl_idname == 'PovrayDiffuseNode':
- intensity=0
- albedo=""
- brilliance=0
- crand=0
+ if link.from_node.bl_idname == "PovrayDiffuseNode":
+ intensity = 0
+ albedo = ""
+ brilliance = 0
+ crand = 0
if link.from_node.inputs["Intensity"].is_linked:
pass
else:
- intensity=link.from_node.inputs["Intensity"].default_value
+ intensity = link.from_node.inputs["Intensity"].default_value
if link.from_node.inputs["Albedo"].is_linked:
pass
else:
- if link.from_node.inputs["Albedo"].default_value == True:
+ if link.from_node.inputs["Albedo"].default_value:
albedo = "albedo"
- file.write(' diffuse %s %.4g\n'%(albedo,intensity))
+ file.write(" diffuse %s %.4g\n" % (albedo, intensity))
if link.from_node.inputs["Brilliance"].is_linked:
pass
else:
- brilliance=link.from_node.inputs["Brilliance"].default_value
- file.write(' brilliance %.4g\n'%brilliance)
+ brilliance = link.from_node.inputs["Brilliance"].default_value
+ file.write(" brilliance %.4g\n" % brilliance)
if link.from_node.inputs["Crand"].is_linked:
pass
else:
- crand=link.from_node.inputs["Crand"].default_value
+ crand = link.from_node.inputs["Crand"].default_value
if crand > 0:
- file.write(' crand %.4g\n'%crand)
-
+ file.write(" crand %.4g\n" % crand)
- if link.from_node.bl_idname == 'PovraySubsurfaceNode':
+ if link.from_node.bl_idname == "PovraySubsurfaceNode":
if scene.povray.sslt_enable:
energy = 0
r = g = b = 0
if link.from_node.inputs["Translucency"].is_linked:
pass
else:
- r,g,b,a=link.from_node.inputs["Translucency"].default_value[:]
+ r, g, b, a = link.from_node.inputs["Translucency"].default_value[:]
if link.from_node.inputs["Energy"].is_linked:
pass
else:
- energy=link.from_node.inputs["Energy"].default_value
- file.write(' subsurface { translucency <%.4g,%.4g,%.4g>*%s }\n'%(r,g,b,energy))
-
-
-
- if link.from_node.bl_idname in {'PovraySpecularNode','PovrayPhongNode'}:
- intensity=0
- albedo=""
- roughness=0
- metallic=0
- phong_size=0
- highlight="specular"
+ energy = link.from_node.inputs["Energy"].default_value
+ file.write(
+ " subsurface { translucency <%.4g,%.4g,%.4g>*%s }\n"
+ % (r, g, b, energy)
+ )
+
+ if link.from_node.bl_idname in {"PovraySpecularNode", "PovrayPhongNode"}:
+ intensity = 0
+ albedo = ""
+ roughness = 0
+ metallic = 0
+ phong_size = 0
+ highlight = "specular"
if link.from_node.inputs["Intensity"].is_linked:
pass
else:
- intensity=link.from_node.inputs["Intensity"].default_value
+ intensity = link.from_node.inputs["Intensity"].default_value
if link.from_node.inputs["Albedo"].is_linked:
pass
else:
- if link.from_node.inputs["Albedo"].default_value == True:
+ if link.from_node.inputs["Albedo"].default_value:
albedo = "albedo"
- if link.from_node.bl_idname in {'PovrayPhongNode'}:
- highlight="phong"
- file.write(' %s %s %.4g\n'%(highlight,albedo,intensity))
+ if link.from_node.bl_idname in {"PovrayPhongNode"}:
+ highlight = "phong"
+ file.write(" %s %s %.4g\n" % (highlight, albedo, intensity))
- if link.from_node.bl_idname in {'PovraySpecularNode'}:
+ if link.from_node.bl_idname in {"PovraySpecularNode"}:
if link.from_node.inputs["Roughness"].is_linked:
pass
else:
- roughness=link.from_node.inputs["Roughness"].default_value
- file.write(' roughness %.6g\n'%roughness)
+ roughness = link.from_node.inputs["Roughness"].default_value
+ file.write(" roughness %.6g\n" % roughness)
- if link.from_node.bl_idname in {'PovrayPhongNode'}:
+ if link.from_node.bl_idname in {"PovrayPhongNode"}:
if link.from_node.inputs["Size"].is_linked:
pass
else:
- phong_size=link.from_node.inputs["Size"].default_value
- file.write(' phong_size %s\n'%phong_size)
+ phong_size = link.from_node.inputs["Size"].default_value
+ file.write(" phong_size %s\n" % phong_size)
if link.from_node.inputs["Metallic"].is_linked:
pass
else:
- metallic=link.from_node.inputs["Metallic"].default_value
- file.write(' metallic %.4g\n'%metallic)
-
- if link.from_node.bl_idname in {'PovrayMirrorNode'}:
- file.write(' reflection {\n')
- color=None
- exponent=0
- metallic=0
- falloff=0
- fresnel=""
- conserve=""
+ metallic = link.from_node.inputs["Metallic"].default_value
+ file.write(" metallic %.4g\n" % metallic)
+
+ if link.from_node.bl_idname in {"PovrayMirrorNode"}:
+ file.write(" reflection {\n")
+ color = None
+ exponent = 0
+ metallic = 0
+ falloff = 0
+ fresnel = ""
+ conserve = ""
if link.from_node.inputs["Color"].is_linked:
pass
else:
- color=link.from_node.inputs["Color"].default_value[:]
- file.write(' <%.4g,%.4g,%.4g>\n'%color)
+ color = link.from_node.inputs["Color"].default_value[:]
+ file.write(" <%.4g,%.4g,%.4g>\n" % color)
if link.from_node.inputs["Exponent"].is_linked:
pass
else:
- exponent=link.from_node.inputs["Exponent"].default_value
- file.write(' exponent %.4g\n'%exponent)
+ exponent = link.from_node.inputs["Exponent"].default_value
+ file.write(" exponent %.4g\n" % exponent)
if link.from_node.inputs["Falloff"].is_linked:
pass
else:
- falloff=link.from_node.inputs["Falloff"].default_value
- file.write(' falloff %.4g\n'%falloff)
+ falloff = link.from_node.inputs["Falloff"].default_value
+ file.write(" falloff %.4g\n" % falloff)
if link.from_node.inputs["Metallic"].is_linked:
pass
else:
- metallic=link.from_node.inputs["Metallic"].default_value
- file.write(' metallic %.4g'%metallic)
+ metallic = link.from_node.inputs["Metallic"].default_value
+ file.write(" metallic %.4g" % metallic)
if link.from_node.inputs["Fresnel"].is_linked:
pass
else:
- if link.from_node.inputs["Fresnel"].default_value==True:
- fresnel="fresnel"
+ if link.from_node.inputs["Fresnel"].default_value:
+ fresnel = "fresnel"
if link.from_node.inputs["Conserve energy"].is_linked:
pass
else:
- if link.from_node.inputs["Conserve energy"].default_value==True:
- conserve="conserve_energy"
+ if link.from_node.inputs["Conserve energy"].default_value:
+ conserve = "conserve_energy"
- file.write(' %s}\n %s\n'%(fresnel,conserve))
+ file.write(" %s}\n %s\n" % (fresnel, conserve))
- if link.from_node.bl_idname == 'PovrayAmbientNode':
- ambient=(0,0,0)
+ if link.from_node.bl_idname == "PovrayAmbientNode":
+ ambient = (0, 0, 0)
if link.from_node.inputs["Ambient"].is_linked:
pass
else:
- ambient=link.from_node.inputs["Ambient"].default_value[:]
- file.write(' ambient <%.4g,%.4g,%.4g>\n'%ambient)
-
- if link.from_node.bl_idname in {'PovrayIridescenceNode'}:
- file.write(' irid {\n')
- amount=0
- thickness=0
- turbulence=0
+ ambient = link.from_node.inputs["Ambient"].default_value[:]
+ file.write(" ambient <%.4g,%.4g,%.4g>\n" % ambient)
+
+ if link.from_node.bl_idname in {"PovrayIridescenceNode"}:
+ file.write(" irid {\n")
+ amount = 0
+ thickness = 0
+ turbulence = 0
if link.from_node.inputs["Amount"].is_linked:
pass
else:
- amount=link.from_node.inputs["Amount"].default_value
- file.write(' %.4g\n'%amount)
+ amount = link.from_node.inputs["Amount"].default_value
+ file.write(" %.4g\n" % amount)
if link.from_node.inputs["Thickness"].is_linked:
pass
else:
- exponent=link.from_node.inputs["Thickness"].default_value
- file.write(' thickness %.4g\n'%thickness)
+ exponent = link.from_node.inputs["Thickness"].default_value
+ file.write(" thickness %.4g\n" % thickness)
if link.from_node.inputs["Turbulence"].is_linked:
pass
else:
- falloff=link.from_node.inputs["Turbulence"].default_value
- file.write(' turbulence %.4g}\n'%turbulence)
+ falloff = link.from_node.inputs["Turbulence"].default_value
+ file.write(" turbulence %.4g}\n" % turbulence)
- file.write('}\n')
+ file.write("}\n")
for node in ntree.nodes:
- povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+ pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayTransformNode" and node.outputs["Transform"].is_linked:
- tx=node.inputs["Translate x"].default_value
- ty=node.inputs["Translate y"].default_value
- tz=node.inputs["Translate z"].default_value
- rx=node.inputs["Rotate x"].default_value
- ry=node.inputs["Rotate y"].default_value
- rz=node.inputs["Rotate z"].default_value
- sx=node.inputs["Scale x"].default_value
- sy=node.inputs["Scale y"].default_value
- sz=node.inputs["Scale z"].default_value
- file.write('#declare %s = transform {\n translate<%.4g,%.4g,%.4g>\n rotate<%.4g,%.4g,%.4g>\n scale<%.4g,%.4g,%.4g>}\n'%(povNodeName,tx,ty,tz,rx,ry,rz,sx,sy,sz))
+ tx = node.inputs["Translate x"].default_value
+ ty = node.inputs["Translate y"].default_value
+ tz = node.inputs["Translate z"].default_value
+ rx = node.inputs["Rotate x"].default_value
+ ry = node.inputs["Rotate y"].default_value
+ rz = node.inputs["Rotate z"].default_value
+ sx = node.inputs["Scale x"].default_value
+ sy = node.inputs["Scale y"].default_value
+ sz = node.inputs["Scale z"].default_value
+ file.write(
+ "#declare %s = transform {\n"
+ " translate<%.4g,%.4g,%.4g>\n"
+ " rotate<%.4g,%.4g,%.4g>\n"
+ " scale<%.4g,%.4g,%.4g>}\n" % (pov_node_name, tx, ty, tz, rx, ry, rz, sx, sy, sz)
+ )
for node in ntree.nodes:
- povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+ pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayColorImageNode" and node.outputs["Pigment"].is_linked:
- declareNodes.append(node.name)
+ declare_nodes.append(node.name)
if node.image == "":
- file.write('#declare %s = pigment { color rgb 0.8}\n'%(povNodeName))
+ file.write("#declare %s = pigment { color rgb 0.8}\n" % (pov_node_name))
else:
- im=bpy.data.images[node.image]
- if im.filepath and os.path.exists(bpy.path.abspath(im.filepath)):
+ im = bpy.data.images[node.image]
+ if im.filepath and path.exists(bpy.path.abspath(im.filepath)): # (os.path)
transform = ""
for link in ntree.links:
- if link.from_node.bl_idname=='PovrayTransformNode' and link.to_node==node:
- povTransName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
- transform="transform {%s}"%povTransName
- uv=""
- if node.map_type=="uv_mapping":
- uv="uv_mapping"
- filepath=bpy.path.abspath(im.filepath)
- file.write('#declare %s = pigment {%s image_map {\n'%(povNodeName,uv))
- premul="off"
+ if (
+ link.from_node.bl_idname == "PovrayTransformNode"
+ and link.to_node == node
+ ):
+ pov_trans_name = (
+ string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ + "_%s" % pov_mat_name
+ )
+ transform = "transform {%s}" % pov_trans_name
+ uv = ""
+ if node.map_type == "uv_mapping":
+ uv = "uv_mapping"
+ filepath = bpy.path.abspath(im.filepath)
+ file.write("#declare %s = pigment {%s image_map {\n" % (pov_node_name, uv))
+ premul = "off"
if node.premultiplied:
- premul="on"
- once=""
+ premul = "on"
+ once = ""
if node.once:
- once="once"
- file.write(' "%s"\n gamma %.6g\n premultiplied %s\n'%(filepath,node.inputs["Gamma"].default_value,premul))
- file.write(' %s\n'%once)
- if node.map_type!="uv_mapping":
- file.write(' map_type %s\n'%(node.map_type))
- file.write(' interpolate %s\n filter all %.4g\n transmit all %.4g\n'%
- (node.interpolate,node.inputs["Filter"].default_value,node.inputs["Transmit"].default_value))
- file.write(' }\n')
- file.write(' %s\n'%transform)
- file.write(' }\n')
+ once = "once"
+ file.write(
+ ' "%s"\n gamma %.6g\n premultiplied %s\n'
+ % (filepath, node.inputs["Gamma"].default_value, premul)
+ )
+ file.write(" %s\n" % once)
+ if node.map_type != "uv_mapping":
+ file.write(" map_type %s\n" % (node.map_type))
+ file.write(
+ " interpolate %s\n filter all %.4g\n transmit all %.4g\n"
+ % (
+ node.interpolate,
+ node.inputs["Filter"].default_value,
+ node.inputs["Transmit"].default_value,
+ )
+ )
+ file.write(" }\n")
+ file.write(" %s\n" % transform)
+ file.write(" }\n")
for node in ntree.nodes:
- povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+ pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayImagePatternNode" and node.outputs["Pattern"].is_linked:
- declareNodes.append(node.name)
+ declare_nodes.append(node.name)
if node.image != "":
- im=bpy.data.images[node.image]
- if im.filepath and os.path.exists(bpy.path.abspath(im.filepath)):
+ im = bpy.data.images[node.image]
+ if im.filepath and path.exists(bpy.path.abspath(im.filepath)):
transform = ""
for link in ntree.links:
- if link.from_node.bl_idname=='PovrayTransformNode' and link.to_node==node:
- povTransName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
- transform="transform {%s}"%povTransName
- uv=""
- if node.map_type=="uv_mapping":
- uv="uv_mapping"
- filepath=bpy.path.abspath(im.filepath)
- file.write('#macro %s() %s image_pattern {\n'%(povNodeName,uv))
- premul="off"
+ if (
+ link.from_node.bl_idname == "PovrayTransformNode"
+ and link.to_node == node
+ ):
+ pov_trans_name = (
+ string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ + "_%s" % pov_mat_name
+ )
+ transform = "transform {%s}" % pov_trans_name
+ uv = ""
+ if node.map_type == "uv_mapping":
+ uv = "uv_mapping"
+ filepath = bpy.path.abspath(im.filepath)
+ file.write("#macro %s() %s image_pattern {\n" % (pov_node_name, uv))
+ premul = "off"
if node.premultiplied:
- premul="on"
- once=""
+ premul = "on"
+ once = ""
if node.once:
- once="once"
- file.write(' "%s"\n gamma %.6g\n premultiplied %s\n'%(filepath,node.inputs["Gamma"].default_value,premul))
- file.write(' %s\n'%once)
- if node.map_type!="uv_mapping":
- file.write(' map_type %s\n'%(node.map_type))
- file.write(' interpolate %s\n'%node.interpolate)
- file.write(' }\n')
- file.write(' %s\n'%transform)
- file.write('#end\n')
+ once = "once"
+ file.write(
+ ' "%s"\n gamma %.6g\n premultiplied %s\n'
+ % (filepath, node.inputs["Gamma"].default_value, premul)
+ )
+ file.write(" %s\n" % once)
+ if node.map_type != "uv_mapping":
+ file.write(" map_type %s\n" % (node.map_type))
+ file.write(" interpolate %s\n" % node.interpolate)
+ file.write(" }\n")
+ file.write(" %s\n" % transform)
+ file.write("#end\n")
for node in ntree.nodes:
- povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+ pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayBumpMapNode" and node.outputs["Normal"].is_linked:
if node.image != "":
- im=bpy.data.images[node.image]
- if im.filepath and os.path.exists(bpy.path.abspath(im.filepath)):
+ im = bpy.data.images[node.image]
+ if im.filepath and path.exists(bpy.path.abspath(im.filepath)):
transform = ""
for link in ntree.links:
- if link.from_node.bl_idname=='PovrayTransformNode' and link.to_node==node:
- povTransName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
- transform="transform {%s}"%povTransName
- uv=""
- if node.map_type=="uv_mapping":
- uv="uv_mapping"
- filepath=bpy.path.abspath(im.filepath)
- file.write('#declare %s = normal {%s bump_map {\n'%(povNodeName,uv))
- once=""
+ if (
+ link.from_node.bl_idname == "PovrayTransformNode"
+ and link.to_node == node
+ ):
+ pov_trans_name = (
+ string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ + "_%s" % pov_mat_name
+ )
+ transform = "transform {%s}" % pov_trans_name
+ uv = ""
+ if node.map_type == "uv_mapping":
+ uv = "uv_mapping"
+ filepath = bpy.path.abspath(im.filepath)
+ file.write("#declare %s = normal {%s bump_map {\n" % (pov_node_name, uv))
+ once = ""
if node.once:
- once="once"
- file.write(' "%s"\n'%filepath)
- file.write(' %s\n'%once)
- if node.map_type!="uv_mapping":
- file.write(' map_type %s\n'%(node.map_type))
- bump_size=node.inputs["Normal"].default_value
+ once = "once"
+ file.write(' "%s"\n' % filepath)
+ file.write(" %s\n" % once)
+ if node.map_type != "uv_mapping":
+ file.write(" map_type %s\n" % (node.map_type))
+ bump_size = node.inputs["Normal"].default_value
if node.inputs["Normal"].is_linked:
pass
- file.write(' interpolate %s\n bump_size %.4g\n'%(node.interpolate,bump_size))
- file.write(' }\n')
- file.write(' %s\n'%transform)
- file.write(' }\n')
- declareNodes.append(node.name)
-
-
+ file.write(
+ " interpolate %s\n bump_size %.4g\n" % (node.interpolate, bump_size)
+ )
+ file.write(" }\n")
+ file.write(" %s\n" % transform)
+ file.write(" }\n")
+ declare_nodes.append(node.name)
for node in ntree.nodes:
- povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+ pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayPigmentNode" and node.outputs["Pigment"].is_linked:
- declareNodes.append(node.name)
- r,g,b=node.inputs["Color"].default_value[:]
- f=node.inputs["Filter"].default_value
- t=node.inputs["Transmit"].default_value
+ declare_nodes.append(node.name)
+ r, g, b = node.inputs["Color"].default_value[:]
+ f = node.inputs["Filter"].default_value
+ t = node.inputs["Transmit"].default_value
if node.inputs["Color"].is_linked:
pass
- file.write('#declare %s = pigment{color srgbft <%.4g,%.4g,%.4g,%.4g,%.4g>}\n'%(povNodeName,r,g,b,f,t))
-
+ file.write(
+ "#declare %s = pigment{color srgbft <%.4g,%.4g,%.4g,%.4g,%.4g>}\n"
+ % (pov_node_name, r, g, b, f, t)
+ )
for node in ntree.nodes:
- povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
+ pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayTextureNode" and node.outputs["Texture"].is_linked:
- declareNodes.append(node.name)
- r,g,b=node.inputs["Pigment"].default_value[:]
- povColName="color rgb <%.4g,%.4g,%.4g>"%(r,g,b)
+ declare_nodes.append(node.name)
+ r, g, b = node.inputs["Pigment"].default_value[:]
+ pov_col_name = "color rgb <%.4g,%.4g,%.4g>" % (r, g, b)
if node.inputs["Pigment"].is_linked:
for link in ntree.links:
- if link.to_node==node and link.to_socket.name=="Pigment":
- povColName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
- file.write('#declare %s = texture{\n pigment{%s}\n'%(povNodeName,povColName))
+ if link.to_node == node and link.to_socket.name == "Pigment":
+ pov_col_name = (
+ string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ + "_%s" % pov_mat_name
+ )
+ file.write("#declare %s = texture{\n pigment{%s}\n" % (pov_node_name, pov_col_name))
if node.inputs["Normal"].is_linked:
for link in ntree.links:
- if link.to_node==node and link.to_socket.name=="Normal" and link.from_node.name in declareNodes:
- povNorName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
- file.write(' normal{%s}\n'%povNorName)
+ if (
+ link.to_node == node
+ and link.to_socket.name == "Normal"
+ and link.from_node.name in declare_nodes
+ ):
+ pov_nor_name = (
+ string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ + "_%s" % pov_mat_name
+ )
+ file.write(" normal{%s}\n" % pov_nor_name)
if node.inputs["Finish"].is_linked:
for link in ntree.links:
- if link.to_node==node and link.to_socket.name=="Finish":
- povFinName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
- file.write(' finish{%s}\n'%povFinName)
- file.write('}\n')
- declareNodes.append(node.name)
+ if link.to_node == node and link.to_socket.name == "Finish":
+ pov_fin_name = (
+ string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ + "_%s" % pov_mat_name
+ )
+ file.write(" finish{%s}\n" % pov_fin_name)
+ file.write("}\n")
+ declare_nodes.append(node.name)
- for i in range(0,len(ntree.nodes)):
+ for i in range(0, len(ntree.nodes)):
for node in ntree.nodes:
- if node.bl_idname in {"ShaderNodeGroup","ShaderTextureMapNode"}:
+ if node.bl_idname in {"ShaderNodeGroup", "ShaderTextureMapNode"}:
for output in node.outputs:
- if output.name=="Texture" and output.is_linked and (node.name not in declareNodes):
- declare=True
+ if (
+ output.name == "Texture"
+ and output.is_linked
+ and (node.name not in declare_nodes)
+ ):
+ declare = True
for link in ntree.links:
- if link.to_node==node and link.to_socket.name not in {"","Color ramp","Mapping","Transform","Modifier"}:
- if link.from_node.name not in declareNodes:
- declare=False
+ if link.to_node == node and link.to_socket.name not in {
+ "",
+ "Color ramp",
+ "Mapping",
+ "Transform",
+ "Modifier",
+ }:
+ if link.from_node.name not in declare_nodes:
+ declare = False
if declare:
- povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName
- uv=""
- warp=""
+ pov_node_name = (
+ string_strip_hyphen(bpy.path.clean_name(node.name))
+ + "_%s" % pov_mat_name
+ )
+ uv = ""
+ warp = ""
for link in ntree.links:
- if link.to_node==node and link.from_node.bl_idname=='PovrayMappingNode' and link.from_node.warp_type!="NONE":
+ if (
+ link.to_node == node
+ and link.from_node.bl_idname == "PovrayMappingNode"
+ and link.from_node.warp_type != "NONE"
+ ):
w_type = link.from_node.warp_type
- if w_type=="uv_mapping":
- uv="uv_mapping"
+ if w_type == "uv_mapping":
+ uv = "uv_mapping"
else:
- tor=""
- if w_type=="toroidal":
- tor="major_radius %.4g"%link.from_node.warp_tor_major_radius
- orient=link.from_node.warp_orientation
- exp=link.from_node.warp_dist_exp
- warp="warp{%s orientation %s dist_exp %.4g %s}"%(w_type,orient,exp,tor)
- if link.from_node.warp_type=="planar":
- warp="warp{%s %s %.4g}"%(w_type,orient,exp)
- if link.from_node.warp_type=="cubic":
- warp="warp{%s}"%w_type
- file.write('#declare %s = texture {%s\n'%(povNodeName,uv))
- pattern=node.inputs[0].default_value
- advanced=""
+ tor = ""
+ if w_type == "toroidal":
+ tor = (
+ "major_radius %.4g"
+ % link.from_node.warp_tor_major_radius
+ )
+ orient = link.from_node.warp_orientation
+ exp = link.from_node.warp_dist_exp
+ warp = "warp{%s orientation %s dist_exp %.4g %s}" % (
+ w_type,
+ orient,
+ exp,
+ tor,
+ )
+ if link.from_node.warp_type == "planar":
+ warp = "warp{%s %s %.4g}" % (w_type, orient, exp)
+ if link.from_node.warp_type == "cubic":
+ warp = "warp{%s}" % w_type
+ file.write("#declare %s = texture {%s\n" % (pov_node_name, uv))
+ pattern = node.inputs[0].default_value
+ advanced = ""
if node.inputs[0].is_linked:
for link in ntree.links:
- if link.to_node==node and link.from_node.bl_idname=='ShaderPatternNode':
+ if (
+ link.to_node == node
+ and link.from_node.bl_idname == "ShaderPatternNode"
+ ):
########### advanced ###############################################
- lfn=link.from_node
- pattern=lfn.pattern
- if pattern == 'agate':
- advanced = 'agate_turb %.4g'%lfn.agate_turb
- if pattern == 'crackle':
- advanced="form <%.4g,%.4g,%.4g>"%(lfn.crackle_form_x,lfn.crackle_form_y,lfn.crackle_form_z)
- advanced+=" metric %.4g"%lfn.crackle_metric
+ lfn = link.from_node
+ pattern = lfn.pattern
+ if pattern == "agate":
+ advanced = "agate_turb %.4g" % lfn.agate_turb
+ if pattern == "crackle":
+ advanced = "form <%.4g,%.4g,%.4g>" % (
+ lfn.crackle_form_x,
+ lfn.crackle_form_y,
+ lfn.crackle_form_z,
+ )
+ advanced += " metric %.4g" % lfn.crackle_metric
if lfn.crackle_solid:
- advanced+=" solid"
- if pattern in {'spiral1', 'spiral2'}:
- advanced='%.4g'%lfn.spiral_arms
- if pattern in {'tiling'}:
- advanced='%.4g'%lfn.tiling_number
- if pattern in {'gradient'}:
- advanced='%s'%lfn.gradient_orient
- if link.to_node==node and link.from_node.bl_idname=='PovrayImagePatternNode':
- povMacroName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
- pattern = "%s()"%povMacroName
- file.write(' %s %s %s\n'%(pattern,advanced,warp))
-
- repeat=""
+ advanced += " solid"
+ if pattern in {"spiral1", "spiral2"}:
+ advanced = "%.4g" % lfn.spiral_arms
+ if pattern in {"tiling"}:
+ advanced = "%.4g" % lfn.tiling_number
+ if pattern in {"gradient"}:
+ advanced = "%s" % lfn.gradient_orient
+ if (
+ link.to_node == node
+ and link.from_node.bl_idname == "PovrayImagePatternNode"
+ ):
+ pov_macro_name = (
+ string_strip_hyphen(
+ bpy.path.clean_name(link.from_node.name)
+ )
+ + "_%s" % pov_mat_name
+ )
+ pattern = "%s()" % pov_macro_name
+ file.write(" %s %s %s\n" % (pattern, advanced, warp))
+
+ repeat = ""
for link in ntree.links:
- if link.to_node==node and link.from_node.bl_idname=='PovrayMultiplyNode':
+ if (
+ link.to_node == node
+ and link.from_node.bl_idname == "PovrayMultiplyNode"
+ ):
if link.from_node.amount_x > 1:
- repeat+="warp{repeat %.4g * x}"%link.from_node.amount_x
+ repeat += "warp{repeat %.4g * x}" % link.from_node.amount_x
if link.from_node.amount_y > 1:
- repeat+=" warp{repeat %.4g * y}"%link.from_node.amount_y
+ repeat += " warp{repeat %.4g * y}" % link.from_node.amount_y
if link.from_node.amount_z > 1:
- repeat+=" warp{repeat %.4g * z}"%link.from_node.amount_z
+ repeat += " warp{repeat %.4g * z}" % link.from_node.amount_z
- transform=""
+ transform = ""
for link in ntree.links:
- if link.to_node==node and link.from_node.bl_idname=='PovrayTransformNode':
- povTransName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
- transform="transform {%s}"%povTransName
- x=0
- y=0
- z=0
- d=0
- e=0
- f=0
- g=0
- h=0
- modifier=False
+ if (
+ link.to_node == node
+ and link.from_node.bl_idname == "PovrayTransformNode"
+ ):
+ pov_trans_name = (
+ string_strip_hyphen(
+ bpy.path.clean_name(link.from_node.name)
+ )
+ + "_%s" % pov_mat_name
+ )
+ transform = "transform {%s}" % pov_trans_name
+ x = 0
+ y = 0
+ z = 0
+ d = 0
+ e = 0
+ f = 0
+ g = 0
+ h = 0
+ modifier = False
for link in ntree.links:
- if link.to_node==node and link.from_node.bl_idname=='PovrayModifierNode':
- modifier=True
+ if (
+ link.to_node == node
+ and link.from_node.bl_idname == "PovrayModifierNode"
+ ):
+ modifier = True
if link.from_node.inputs["Turb X"].is_linked:
pass
else:
@@ -1800,66 +1604,135 @@ def write_nodes(scene,povMatName,ntree,file):
else:
h = link.from_node.inputs["Phase"].default_value
- turb = "turbulence <%.4g,%.4g,%.4g>"%(x,y,z)
- octv = "octaves %s"%d
- lmbd = "lambda %.4g"%e
- omg = "omega %.4g"%f
- freq = "frequency %.4g"%g
- pha = "phase %.4g"%h
-
-
- file.write('\n')
- if pattern not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
- file.write(' texture_map {\n')
+ turb = "turbulence <%.4g,%.4g,%.4g>" % (x, y, z)
+ octv = "octaves %s" % d
+ lmbd = "lambda %.4g" % e
+ omg = "omega %.4g" % f
+ freq = "frequency %.4g" % g
+ pha = "phase %.4g" % h
+
+ file.write("\n")
+ if pattern not in {
+ "checker",
+ "hexagon",
+ "square",
+ "triangular",
+ "brick",
+ }:
+ file.write(" texture_map {\n")
if node.inputs["Color ramp"].is_linked:
for link in ntree.links:
- if link.to_node==node and link.from_node.bl_idname=="ShaderNodeValToRGB":
+ if (
+ link.to_node == node
+ and link.from_node.bl_idname == "ShaderNodeValToRGB"
+ ):
els = link.from_node.color_ramp.elements
- n=-1
+ n = -1
for el in els:
- n+=1
- povInMatName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s_%s"%(n,povMatName)
- default=True
+ n += 1
+ pov_in_mat_name = string_strip_hyphen(
+ bpy.path.clean_name(link.from_node.name)
+ ) + "_%s_%s" % (n, pov_mat_name)
+ default = True
for ilink in ntree.links:
- if ilink.to_node==node and ilink.to_socket.name == str(n):
- default=False
- povInMatName=string_strip_hyphen(bpy.path.clean_name(ilink.from_node.name))+"_%s"%povMatName
+ if (
+ ilink.to_node == node
+ and ilink.to_socket.name == str(n)
+ ):
+ default = False
+ pov_in_mat_name = (
+ string_strip_hyphen(
+ bpy.path.clean_name(
+ ilink.from_node.name
+ )
+ )
+ + "_%s" % pov_mat_name
+ )
if default:
- r,g,b,a=el.color[:]
- file.write(' #declare %s = texture{pigment{color srgbt <%.4g,%.4g,%.4g,%.4g>}};\n'%(povInMatName,r,g,b,1-a))
- file.write(' [%s %s]\n'%(el.position,povInMatName))
+ r, g, b, a = el.color[:]
+ file.write(
+ " #declare %s = texture{"
+ "pigment{"
+ "color srgbt <%.4g,%.4g,%.4g,%.4g>}};\n"
+ % (pov_in_mat_name, r, g, b, 1 - a)
+ )
+ file.write(
+ " [%s %s]\n" % (el.position, pov_in_mat_name)
+ )
else:
- els=[[0,0,0,0],[1,1,1,1]]
- for i in range(0,2):
- povInMatName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s_%s"%(i,povMatName)
- default=True
+ els = [[0, 0, 0, 0], [1, 1, 1, 1]]
+ for t in range(0, 2):
+ pov_in_mat_name = string_strip_hyphen(
+ bpy.path.clean_name(link.from_node.name)
+ ) + "_%s_%s" % (t, pov_mat_name)
+ default = True
for ilink in ntree.links:
- if ilink.to_node==node and ilink.to_socket.name == str(i):
- default=False
- povInMatName=string_strip_hyphen(bpy.path.clean_name(ilink.from_node.name))+"_%s"%povMatName
+ if ilink.to_node == node and ilink.to_socket.name == str(t):
+ default = False
+ pov_in_mat_name = (
+ string_strip_hyphen(
+ bpy.path.clean_name(ilink.from_node.name)
+ )
+ + "_%s" % pov_mat_name
+ )
if default:
- r,g,b=els[i][1],els[i][2],els[i][3]
- if pattern not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
- file.write(' #declare %s = texture{pigment{color rgb <%.4g,%.4g,%.4g>}};\n'%(povInMatName,r,g,b))
+ r, g, b = els[t][1], els[t][2], els[t][3]
+ if pattern not in {
+ "checker",
+ "hexagon",
+ "square",
+ "triangular",
+ "brick",
+ }:
+ file.write(
+ " #declare %s = texture{pigment{color rgb <%.4g,%.4g,%.4g>}};\n"
+ % (pov_in_mat_name, r, g, b)
+ )
else:
- file.write(' texture{pigment{color rgb <%.4g,%.4g,%.4g>}}\n'%(r,g,b))
- if pattern not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
- file.write(' [%s %s]\n'%(els[i][0],povInMatName))
+ file.write(
+ " texture{pigment{color rgb <%.4g,%.4g,%.4g>}}\n"
+ % (r, g, b)
+ )
+ if pattern not in {
+ "checker",
+ "hexagon",
+ "square",
+ "triangular",
+ "brick",
+ }:
+ file.write(" [%s %s]\n" % (els[t][0], pov_in_mat_name))
else:
- if default==False:
- file.write(' texture{%s}\n'%povInMatName)
- if pattern not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
- file.write('}\n')
- if pattern == 'brick':
- file.write("brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"%(node.brick_size_x,
- node.brick_size_y, node.brick_size_z, node.brick_mortar))
- file.write(' %s %s'%(repeat,transform))
+ if not default:
+ file.write(" texture{%s}\n" % pov_in_mat_name)
+ if pattern not in {
+ "checker",
+ "hexagon",
+ "square",
+ "triangular",
+ "brick",
+ }:
+ file.write("}\n")
+ if pattern == "brick":
+ file.write(
+ "brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"
+ % (
+ node.brick_size_x,
+ node.brick_size_y,
+ node.brick_size_z,
+ node.brick_mortar,
+ )
+ )
+ file.write(" %s %s" % (repeat, transform))
if modifier:
- file.write(' %s %s %s %s %s %s'%(turb,octv,lmbd,omg,freq,pha))
- file.write('}\n')
- declareNodes.append(node.name)
+ file.write(
+ " %s %s %s %s %s %s" % (turb, octv, lmbd, omg, freq, pha)
+ )
+ file.write("}\n")
+ declare_nodes.append(node.name)
for link in ntree.links:
- if link.to_node.bl_idname == "PovrayOutputNode" and link.from_node.name in declareNodes:
- povMatNodeName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
- file.write('#declare %s = %s\n'%(povMatName,povMatNodeName))
+ if link.to_node.bl_idname == "PovrayOutputNode" and link.from_node.name in declare_nodes:
+ pov_mat_node_name = (
+ string_strip_hyphen(bpy.path.clean_name(link.from_node.name)) + "_%s" % pov_mat_name
+ )
+ file.write("#declare %s = %s\n" % (pov_mat_name, pov_mat_node_name))
diff --git a/render_povray/shading_gui.py b/render_povray/shading_gui.py
new file mode 100755
index 00000000..428542c8
--- /dev/null
+++ b/render_povray/shading_gui.py
@@ -0,0 +1,680 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+""""User interface for shaders exported to POV textures."""
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import Operator, Menu, Panel
+from bl_operators.presets import AddPresetBase
+
+# Example of wrapping every class 'as is' except some
+from bl_ui import properties_material
+
+for member in dir(properties_material):
+ subclass = getattr(properties_material, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_material
+
+from .shading_properties import check_material
+
+
+def simple_material(mat):
+ """Test if a material uses nodes"""
+ if (mat is not None) and (not mat.use_nodes):
+ return True
+ return False
+
+
+class MaterialButtonsPanel:
+ """Use this class to define buttons from the material tab of
+ properties window."""
+
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "material"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ rd = context.scene.render
+ return mat and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class MATERIAL_MT_POV_sss_presets(Menu):
+ """Use this class to define pov sss preset menu."""
+
+ bl_label = "SSS Presets"
+ preset_subdir = "pov/material/sss"
+ preset_operator = "script.execute_preset"
+ draw = bpy.types.Menu.draw_preset
+
+
+class MATERIAL_OT_POV_sss_add_preset(AddPresetBase, Operator):
+ """Add an SSS Preset"""
+
+ bl_idname = "material.sss_preset_add"
+ bl_label = "Add SSS Preset"
+ preset_menu = "MATERIAL_MT_POV_sss_presets"
+
+ # variable used for all preset values
+ preset_defines = ["material = bpy.context.material"]
+
+ # properties to store in the preset
+ preset_values = [
+ "material.pov_subsurface_scattering.radius",
+ "material.pov_subsurface_scattering.color",
+ ]
+
+ # where to store the preset
+ preset_subdir = "pov/material/sss"
+
+
+class MATERIAL_PT_POV_sss(MaterialButtonsPanel, Panel):
+ """Use this class to define pov sss buttons panel."""
+
+ bl_label = "Subsurface Scattering"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return (
+ check_material(mat)
+ and (mat.pov.type in {'SURFACE', 'WIRE'})
+ and (engine in cls.COMPAT_ENGINES)
+ )
+
+ def draw_header(self, context):
+ mat = context.material # FORMERLY : #active_node_mat(context.material)
+ sss = mat.pov_subsurface_scattering
+
+ self.layout.active = not mat.pov.use_shadeless
+ self.layout.prop(sss, "use", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = context.material # FORMERLY : #active_node_mat(context.material)
+ sss = mat.pov_subsurface_scattering
+
+ layout.active = (sss.use) and (not mat.pov.use_shadeless)
+
+ row = layout.row().split()
+ sub = row.row(align=True).split(align=True, factor=0.75)
+ sub.menu(MATERIAL_MT_POV_sss_presets.__name__, text=MATERIAL_MT_POV_sss_presets.bl_label)
+ sub.operator(MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='ADD')
+ sub.operator(
+ MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='REMOVE'
+ ).remove_active = True
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(sss, "ior")
+ col.prop(sss, "scale")
+ col.prop(sss, "color", text="")
+ col.prop(sss, "radius", text="RGB Radius", expand=True)
+
+ col = split.column()
+ sub = col.column(align=True)
+ sub.label(text="Blend:")
+ sub.prop(sss, "color_factor", text="Color")
+ sub.prop(sss, "texture_factor", text="Texture")
+ sub.label(text="Scattering Weight:")
+ sub.prop(sss, "front")
+ sub.prop(sss, "back")
+ col.separator()
+ col.prop(sss, "error_threshold", text="Error")
+
+
+class MATERIAL_PT_POV_activate_node(MaterialButtonsPanel, Panel):
+ """Use this class to define an activate pov nodes button."""
+
+ bl_label = "Activate Node Settings"
+ bl_context = "material"
+ bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ mat = context.material
+ return (
+ mat
+ and mat.pov.type == "SURFACE"
+ and (engine in cls.COMPAT_ENGINES)
+ and not (mat.pov.material_use_nodes or mat.use_nodes)
+ )
+
+ def draw(self, context):
+ layout = self.layout
+ # layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
+ # the above replaced with a context hook below:
+ layout.operator(
+ "WM_OT_context_toggle", text="Use POV-Ray Nodes", icon='NODETREE'
+ ).data_path = "material.pov.material_use_nodes"
+
+
+class MATERIAL_PT_POV_active_node(MaterialButtonsPanel, Panel):
+ """Use this class to show pov active node properties buttons."""
+
+ bl_label = "Active Node Settings"
+ bl_context = "material"
+ bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ mat = context.material
+ return (
+ mat
+ and mat.pov.type == "SURFACE"
+ and (engine in cls.COMPAT_ENGINES)
+ and mat.pov.material_use_nodes
+ )
+
+ def draw(self, context):
+ layout = self.layout
+ mat = context.material
+ node_tree = mat.node_tree
+ if node_tree:
+ node = node_tree.nodes.active
+ if mat.use_nodes:
+ if node:
+ layout.prop(mat.pov, "material_active_node")
+ if node.bl_idname == "PovrayMaterialNode":
+ layout.context_pointer_set("node", node)
+ if hasattr(node, "draw_buttons_ext"):
+ node.draw_buttons_ext(context, layout)
+ elif hasattr(node, "draw_buttons"):
+ node.draw_buttons(context, layout)
+ value_inputs = [
+ socket
+ for socket in node.inputs
+ if socket.enabled and not socket.is_linked
+ ]
+ if value_inputs:
+ layout.separator()
+ layout.label(text="Inputs:")
+ for socket in value_inputs:
+ row = layout.row()
+ socket.draw(context, row, node, socket.name)
+ else:
+ layout.context_pointer_set("node", node)
+ if hasattr(node, "draw_buttons_ext"):
+ node.draw_buttons_ext(context, layout)
+ elif hasattr(node, "draw_buttons"):
+ node.draw_buttons(context, layout)
+ value_inputs = [
+ socket
+ for socket in node.inputs
+ if socket.enabled and not socket.is_linked
+ ]
+ if value_inputs:
+ layout.separator()
+ layout.label(text="Inputs:")
+ for socket in value_inputs:
+ row = layout.row()
+ socket.draw(context, row, node, socket.name)
+ else:
+ layout.label(text="No active nodes!")
+
+
+class MATERIAL_PT_POV_specular(MaterialButtonsPanel, Panel):
+ """Use this class to define standard material specularity (highlights) buttons."""
+
+ bl_label = "Specular"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return (
+ check_material(mat)
+ and (mat.pov.type in {'SURFACE', 'WIRE'})
+ and (engine in cls.COMPAT_ENGINES)
+ )
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = context.material.pov
+
+ layout.active = not mat.use_shadeless
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(mat, "specular_color", text="")
+ col.prop(mat, "specular_intensity", text="Intensity")
+
+ col = split.column()
+ col.prop(mat, "specular_shader", text="")
+ col.prop(mat, "use_specular_ramp", text="Ramp")
+
+ col = layout.column()
+ if mat.specular_shader in {'COOKTORR', 'PHONG'}:
+ col.prop(mat, "specular_hardness", text="Hardness")
+ elif mat.specular_shader == 'BLINN':
+ row = col.row()
+ row.prop(mat, "specular_hardness", text="Hardness")
+ row.prop(mat, "specular_ior", text="IOR")
+ elif mat.specular_shader == 'WARDISO':
+ col.prop(mat, "specular_slope", text="Slope")
+ elif mat.specular_shader == 'TOON':
+ row = col.row()
+ row.prop(mat, "specular_toon_size", text="Size")
+ row.prop(mat, "specular_toon_smooth", text="Smooth")
+
+ if mat.use_specular_ramp:
+ layout.separator()
+ layout.template_color_ramp(mat, "specular_ramp", expand=True)
+ layout.separator()
+
+ row = layout.row()
+ row.prop(mat, "specular_ramp_input", text="Input")
+ row.prop(mat, "specular_ramp_blend", text="Blend")
+
+ layout.prop(mat, "specular_ramp_factor", text="Factor")
+
+
+class MATERIAL_PT_POV_mirror(MaterialButtonsPanel, Panel):
+ """Use this class to define standard material reflectivity (mirror) buttons."""
+
+ bl_label = "Mirror"
+ bl_options = {'DEFAULT_CLOSED'}
+ bl_idname = "MATERIAL_PT_POV_raytrace_mirror"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return (
+ check_material(mat)
+ and (mat.pov.type in {'SURFACE', 'WIRE'})
+ and (engine in cls.COMPAT_ENGINES)
+ )
+
+ def draw_header(self, context):
+ mat = context.material
+ raym = mat.pov_raytrace_mirror
+
+ self.layout.prop(raym, "use", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = context.material # Formerly : #mat = active_node_mat(context.material)
+ raym = mat.pov_raytrace_mirror
+
+ layout.active = raym.use
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(raym, "reflect_factor")
+ col.prop(raym, "mirror_color", text="")
+
+ col = split.column()
+ col.prop(raym, "fresnel")
+ sub = col.column()
+ sub.active = raym.fresnel > 0.0
+ sub.prop(raym, "fresnel_factor", text="Blend")
+
+ split = layout.split()
+
+ col = split.column()
+ col.separator()
+ col.prop(raym, "depth")
+ col.prop(raym, "distance", text="Max Dist")
+ col.separator()
+ sub = col.split(factor=0.4)
+ sub.active = raym.distance > 0.0
+ sub.label(text="Fade To:")
+ sub.prop(raym, "fade_to", text="")
+
+ col = split.column()
+ col.label(text="Gloss:")
+ col.prop(raym, "gloss_factor", text="Amount")
+ sub = col.column()
+ sub.active = raym.gloss_factor < 1.0
+ sub.prop(raym, "gloss_threshold", text="Threshold")
+ sub.prop(raym, "gloss_samples", text="Noise")
+ sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
+
+
+class MATERIAL_PT_POV_transp(MaterialButtonsPanel, Panel):
+ """Use this class to define pov material transparency (alpha) buttons."""
+
+ bl_label = "Transparency"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return (
+ check_material(mat)
+ and (mat.pov.type in {'SURFACE', 'WIRE'})
+ and (engine in cls.COMPAT_ENGINES)
+ )
+
+ def draw_header(self, context):
+ mat = context.material
+
+ if simple_material(mat):
+ self.layout.prop(mat.pov, "use_transparency", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ base_mat = context.material
+ mat = context.material # FORMERLY active_node_mat(context.material)
+ rayt = mat.pov_raytrace_transparency
+
+ if simple_material(base_mat):
+ row = layout.row()
+ row.active = mat.pov.use_transparency
+ row.prop(mat.pov, "transparency_method", expand=True)
+
+ split = layout.split()
+ split.active = base_mat.pov.use_transparency
+
+ col = split.column()
+ col.prop(mat.pov, "alpha")
+ row = col.row()
+ row.active = (base_mat.pov.transparency_method != 'MASK') and (not mat.pov.use_shadeless)
+ row.prop(mat.pov, "specular_alpha", text="Specular")
+
+ col = split.column()
+ col.active = not mat.pov.use_shadeless
+ col.prop(rayt, "fresnel")
+ sub = col.column()
+ sub.active = rayt.fresnel > 0.0
+ sub.prop(rayt, "fresnel_factor", text="Blend")
+
+ if base_mat.pov.transparency_method == 'RAYTRACE':
+ layout.separator()
+ split = layout.split()
+ split.active = base_mat.pov.use_transparency
+
+ col = split.column()
+ col.prop(rayt, "ior")
+ col.prop(rayt, "filter")
+ col.prop(rayt, "falloff")
+ col.prop(rayt, "depth_max")
+ col.prop(rayt, "depth")
+
+ col = split.column()
+ col.label(text="Gloss:")
+ col.prop(rayt, "gloss_factor", text="Amount")
+ sub = col.column()
+ sub.active = rayt.gloss_factor < 1.0
+ sub.prop(rayt, "gloss_threshold", text="Threshold")
+ sub.prop(rayt, "gloss_samples", text="Samples")
+
+
+class MATERIAL_PT_POV_reflection(MaterialButtonsPanel, Panel):
+ """Use this class to define more pov specific reflectivity buttons."""
+
+ bl_label = "POV-Ray Reflection"
+ bl_parent_id = "MATERIAL_PT_POV_raytrace_mirror"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ mat = context.material
+ return (
+ mat
+ and mat.pov.type == "SURFACE"
+ and (engine in cls.COMPAT_ENGINES)
+ and not (mat.pov.material_use_nodes or mat.use_nodes)
+ )
+
+ def draw(self, context):
+ layout = self.layout
+ mat = context.material
+ col = layout.column()
+ col.prop(mat.pov, "irid_enable")
+ if mat.pov.irid_enable:
+ col = layout.column()
+ col.prop(mat.pov, "irid_amount", slider=True)
+ col.prop(mat.pov, "irid_thickness", slider=True)
+ col.prop(mat.pov, "irid_turbulence", slider=True)
+ col.prop(mat.pov, "conserve_energy")
+ col2 = col.split().column()
+
+ if not mat.pov_raytrace_mirror.use:
+ col2.label(text="Please Check Mirror settings :")
+ col2.active = mat.pov_raytrace_mirror.use
+ col2.prop(mat.pov, "mirror_use_IOR")
+ if mat.pov.mirror_use_IOR:
+ col2.alignment = 'CENTER'
+ col2.label(text="The current Raytrace ")
+ col2.label(text="Transparency IOR is: " + str(mat.pov_raytrace_transparency.ior))
+ col2.prop(mat.pov, "mirror_metallic")
+
+
+'''
+#group some native Blender (SSS) and POV (Fade)settings under such a parent panel?
+class MATERIAL_PT_POV_interior(MaterialButtonsPanel, Panel):
+ bl_label = "POV-Ray Interior"
+ bl_idname = "material.pov_interior"
+ #bl_parent_id = "material.absorption"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ mat=context.material
+ return mat and mat.pov.type == "SURFACE" and (engine in cls.COMPAT_ENGINES) and not (mat.pov.material_use_nodes or mat.use_nodes)
+
+
+ def draw_header(self, context):
+ mat = context.material
+'''
+
+
+class MATERIAL_PT_POV_fade_color(MaterialButtonsPanel, Panel):
+ """Use this class to define pov fading (absorption) color buttons."""
+
+ bl_label = "POV-Ray Absorption"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ # bl_parent_id = "material.pov_interior"
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ mat = context.material
+ return (
+ mat
+ and mat.pov.type == "SURFACE"
+ and (engine in cls.COMPAT_ENGINES)
+ and not (mat.pov.material_use_nodes or mat.use_nodes)
+ )
+
+ def draw_header(self, context):
+ mat = context.material
+
+ self.layout.prop(mat.pov, "interior_fade_color", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ mat = context.material
+ # layout.active = mat.pov.interior_fade_color
+ if mat.pov.interior_fade_color != (0.0, 0.0, 0.0):
+ layout.label(text="Raytrace transparency")
+ layout.label(text="depth max Limit needs")
+ layout.label(text="to be non zero to fade")
+
+
+class MATERIAL_PT_POV_caustics(MaterialButtonsPanel, Panel):
+ """Use this class to define pov caustics buttons."""
+
+ bl_label = "Caustics"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ mat = context.material
+ return (
+ mat
+ and mat.pov.type == "SURFACE"
+ and (engine in cls.COMPAT_ENGINES)
+ and not (mat.pov.material_use_nodes or mat.use_nodes)
+ )
+
+ def draw_header(self, context):
+ mat = context.material
+ if mat.pov.caustics_enable:
+ self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER_SEL")
+ else:
+ self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER")
+
+ def draw(self, context):
+
+ layout = self.layout
+
+ mat = context.material
+ layout.active = mat.pov.caustics_enable
+ col = layout.column()
+ if mat.pov.caustics_enable:
+ col.prop(mat.pov, "refraction_caustics")
+ if mat.pov.refraction_caustics:
+
+ col.prop(mat.pov, "refraction_type", text="")
+
+ if mat.pov.refraction_type == "1":
+ col.prop(mat.pov, "fake_caustics_power", slider=True)
+ elif mat.pov.refraction_type == "2":
+ col.prop(mat.pov, "photons_dispersion", slider=True)
+ col.prop(mat.pov, "photons_dispersion_samples", slider=True)
+ col.prop(mat.pov, "photons_reflection")
+
+ if not mat.pov.refraction_caustics and not mat.pov.photons_reflection:
+ col = layout.column()
+ col.alignment = 'CENTER'
+ col.label(text="Caustics override is on, ")
+ col.label(text="but you didn't chose any !")
+
+
+class MATERIAL_PT_strand(MaterialButtonsPanel, Panel):
+ """Use this class to define Blender strand antialiasing buttons."""
+
+ bl_label = "Strand"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return (
+ mat and (mat.pov.type in {'SURFACE', 'WIRE', 'HALO'}) and (engine in cls.COMPAT_ENGINES)
+ )
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = context.material # don't use node material
+ tan = mat.strand
+
+ split = layout.split()
+
+ col = split.column()
+ sub = col.column(align=True)
+ sub.label(text="Size:")
+ sub.prop(tan, "root_size", text="Root")
+ sub.prop(tan, "tip_size", text="Tip")
+ sub.prop(tan, "size_min", text="Minimum")
+ sub.prop(tan, "use_blender_units")
+ sub = col.column()
+ sub.active = not mat.pov.use_shadeless
+ sub.prop(tan, "use_tangent_shading")
+ col.prop(tan, "shape")
+
+ col = split.column()
+ col.label(text="Shading:")
+ col.prop(tan, "width_fade")
+ ob = context.object
+ if ob and ob.type == 'MESH':
+ col.prop_search(tan, "uv_layer", ob.data, "uv_layers", text="")
+ else:
+ col.prop(tan, "uv_layer", text="")
+ col.separator()
+ sub = col.column()
+ sub.active = not mat.pov.use_shadeless
+ sub.label(text="Surface diffuse:")
+ sub = col.column()
+ sub.prop(tan, "blend_distance", text="Distance")
+
+
+class MATERIAL_PT_POV_replacement_text(MaterialButtonsPanel, Panel):
+ """Use this class to define pov custom code declared name field."""
+
+ bl_label = "Custom POV Code"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+ mat = context.material
+ col = layout.column()
+ col.alignment = 'RIGHT'
+ col.label(text="Override properties with this")
+ col.label(text="text editor {pov code} block")
+ layout.prop(mat.pov, "replacement_text", text="#declare name", icon='SYNTAX_ON')
+
+
+classes = (
+ MATERIAL_PT_POV_sss,
+ MATERIAL_MT_POV_sss_presets,
+ MATERIAL_OT_POV_sss_add_preset,
+ MATERIAL_PT_strand,
+ MATERIAL_PT_POV_activate_node,
+ MATERIAL_PT_POV_active_node,
+ MATERIAL_PT_POV_specular,
+ MATERIAL_PT_POV_mirror,
+ MATERIAL_PT_POV_transp,
+ MATERIAL_PT_POV_reflection,
+ ## MATERIAL_PT_POV_interior,
+ MATERIAL_PT_POV_fade_color,
+ MATERIAL_PT_POV_caustics,
+ MATERIAL_PT_POV_replacement_text,
+)
+
+
+def register():
+
+ for cls in classes:
+ register_class(cls)
+
+
+def unregister():
+
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/shading_nodes.py b/render_povray/shading_nodes.py
new file mode 100755
index 00000000..2e8484f9
--- /dev/null
+++ b/render_povray/shading_nodes.py
@@ -0,0 +1,2011 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+""""Nodes based User interface for shaders exported to POV textures."""
+import bpy
+
+from bpy.utils import register_class, unregister_class
+from bpy.types import Menu, Node, NodeSocket, CompositorNodeTree, TextureNodeTree, Operator
+from bpy.props import (
+ StringProperty,
+ BoolProperty,
+ IntProperty,
+ FloatProperty,
+ FloatVectorProperty,
+ EnumProperty,
+)
+import nodeitems_utils
+from nodeitems_utils import NodeCategory, NodeItem
+
+
+###############################################################################
+# Pov Nodes init
+###############################################################################
+
+
+class PovraySocketUniversal(NodeSocket):
+ bl_idname = "PovraySocketUniversal"
+ bl_label = "Povray Socket"
+ value_unlimited: bpy.props.FloatProperty(default=0.0)
+ value_0_1: bpy.props.FloatProperty(min=0.0, max=1.0, default=0.0)
+ value_0_10: bpy.props.FloatProperty(min=0.0, max=10.0, default=0.0)
+ value_000001_10: bpy.props.FloatProperty(min=0.000001, max=10.0, default=0.0)
+ value_1_9: bpy.props.IntProperty(min=1, max=9, default=1)
+ value_0_255: bpy.props.IntProperty(min=0, max=255, default=0)
+ percent: bpy.props.FloatProperty(min=0.0, max=100.0, default=0.0)
+
+ def draw(self, context, layout, node, text):
+ space = context.space_data
+ tree = space.edit_tree
+ links = tree.links
+ if self.is_linked:
+ value = []
+ for link in links:
+ if link.from_node == node:
+ inps = link.to_node.inputs
+ for inp in inps:
+ if inp.bl_idname == "PovraySocketFloat_0_1" and inp.is_linked:
+ prop = "value_0_1"
+ if prop not in value:
+ value.append(prop)
+ if inp.bl_idname == "PovraySocketFloat_000001_10" and inp.is_linked:
+ prop = "value_000001_10"
+ if prop not in value:
+ value.append(prop)
+ if inp.bl_idname == "PovraySocketFloat_0_10" and inp.is_linked:
+ prop = "value_0_10"
+ if prop not in value:
+ value.append(prop)
+ if inp.bl_idname == "PovraySocketInt_1_9" and inp.is_linked:
+ prop = "value_1_9"
+ if prop not in value:
+ value.append(prop)
+ if inp.bl_idname == "PovraySocketInt_0_255" and inp.is_linked:
+ prop = "value_0_255"
+ if prop not in value:
+ value.append(prop)
+ if inp.bl_idname == "PovraySocketFloatUnlimited" and inp.is_linked:
+ prop = "value_unlimited"
+ if prop not in value:
+ value.append(prop)
+ if len(value) == 1:
+ layout.prop(self, "%s" % value[0], text=text)
+ else:
+ layout.prop(self, "percent", text="Percent")
+ else:
+ layout.prop(self, "percent", text=text)
+
+ def draw_color(self, context, node):
+ return (1, 0, 0, 1)
+
+
+class PovraySocketFloat_0_1(NodeSocket):
+ bl_idname = "PovraySocketFloat_0_1"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.FloatProperty(
+ description="Input node Value_0_1", min=0, max=1, default=0
+ )
+
+ def draw(self, context, layout, node, text):
+ if self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text, slider=True)
+
+ def draw_color(self, context, node):
+ return (0.5, 0.7, 0.7, 1)
+
+
+class PovraySocketFloat_0_10(NodeSocket):
+ bl_idname = "PovraySocketFloat_0_10"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.FloatProperty(
+ description="Input node Value_0_10", min=0, max=10, default=0
+ )
+
+ def draw(self, context, layout, node, text):
+ if node.bl_idname == "ShaderNormalMapNode" and node.inputs[2].is_linked:
+ layout.label(text="")
+ self.hide_value = True
+ if self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text, slider=True)
+
+ def draw_color(self, context, node):
+ return (0.65, 0.65, 0.65, 1)
+
+
+class PovraySocketFloat_10(NodeSocket):
+ bl_idname = "PovraySocketFloat_10"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.FloatProperty(
+ description="Input node Value_10", min=-10, max=10, default=0
+ )
+
+ def draw(self, context, layout, node, text):
+ if node.bl_idname == "ShaderNormalMapNode" and node.inputs[2].is_linked:
+ layout.label(text="")
+ self.hide_value = True
+ if self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text, slider=True)
+
+ def draw_color(self, context, node):
+ return (0.65, 0.65, 0.65, 1)
+
+
+class PovraySocketFloatPositive(NodeSocket):
+ bl_idname = "PovraySocketFloatPositive"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.FloatProperty(
+ description="Input Node Value Positive", min=0.0, default=0
+ )
+
+ def draw(self, context, layout, node, text):
+ if self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text, slider=True)
+
+ def draw_color(self, context, node):
+ return (0.045, 0.005, 0.136, 1)
+
+
+class PovraySocketFloat_000001_10(NodeSocket):
+ bl_idname = "PovraySocketFloat_000001_10"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.FloatProperty(min=0.000001, max=10, default=0.000001)
+
+ def draw(self, context, layout, node, text):
+ if self.is_output or self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text, slider=True)
+
+ def draw_color(self, context, node):
+ return (1, 0, 0, 1)
+
+
+class PovraySocketFloatUnlimited(NodeSocket):
+ bl_idname = "PovraySocketFloatUnlimited"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.FloatProperty(default=0.0)
+
+ def draw(self, context, layout, node, text):
+ if self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text, slider=True)
+
+ def draw_color(self, context, node):
+ return (0.7, 0.7, 1, 1)
+
+
+class PovraySocketInt_1_9(NodeSocket):
+ bl_idname = "PovraySocketInt_1_9"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.IntProperty(
+ description="Input node Value_1_9", min=1, max=9, default=6
+ )
+
+ def draw(self, context, layout, node, text):
+ if self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text)
+
+ def draw_color(self, context, node):
+ return (1, 0.7, 0.7, 1)
+
+
+class PovraySocketInt_0_256(NodeSocket):
+ bl_idname = "PovraySocketInt_0_256"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.IntProperty(min=0, max=255, default=0)
+
+ def draw(self, context, layout, node, text):
+ if self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text)
+
+ def draw_color(self, context, node):
+ return (0.5, 0.5, 0.5, 1)
+
+
+class PovraySocketPattern(NodeSocket):
+ bl_idname = "PovraySocketPattern"
+ bl_label = "Povray Socket"
+
+ default_value: bpy.props.EnumProperty(
+ name="Pattern",
+ description="Select the pattern",
+ items=(
+ ("boxed", "Boxed", ""),
+ ("brick", "Brick", ""),
+ ("cells", "Cells", ""),
+ ("checker", "Checker", ""),
+ ("granite", "Granite", ""),
+ ("leopard", "Leopard", ""),
+ ("marble", "Marble", ""),
+ ("onion", "Onion", ""),
+ ("planar", "Planar", ""),
+ ("quilted", "Quilted", ""),
+ ("ripples", "Ripples", ""),
+ ("radial", "Radial", ""),
+ ("spherical", "Spherical", ""),
+ ("spotted", "Spotted", ""),
+ ("waves", "Waves", ""),
+ ("wood", "Wood", ""),
+ ("wrinkles", "Wrinkles", ""),
+ ),
+ default="granite",
+ )
+
+ def draw(self, context, layout, node, text):
+ if self.is_output or self.is_linked:
+ layout.label(text="Pattern")
+ else:
+ layout.prop(self, "default_value", text=text)
+
+ def draw_color(self, context, node):
+ return (1, 1, 1, 1)
+
+
+class PovraySocketColor(NodeSocket):
+ bl_idname = "PovraySocketColor"
+ bl_label = "Povray Socket"
+
+ default_value: FloatVectorProperty(
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(0.0, 0.0, 0.0),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ def draw(self, context, layout, node, text):
+ if self.is_output or self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text)
+
+ def draw_color(self, context, node):
+ return (1, 1, 0, 1)
+
+
+class PovraySocketColorRGBFT(NodeSocket):
+ bl_idname = "PovraySocketColorRGBFT"
+ bl_label = "Povray Socket"
+
+ default_value: FloatVectorProperty(
+ precision=4,
+ step=0.01,
+ min=0,
+ soft_max=1,
+ default=(0.0, 0.0, 0.0),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+ f: bpy.props.FloatProperty(default=0.0, min=0.0, max=1.0)
+ t: bpy.props.FloatProperty(default=0.0, min=0.0, max=1.0)
+
+ def draw(self, context, layout, node, text):
+ if self.is_output or self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text=text)
+
+ def draw_color(self, context, node):
+ return (1, 1, 0, 1)
+
+
+class PovraySocketTexture(NodeSocket):
+ bl_idname = "PovraySocketTexture"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.IntProperty()
+
+ def draw(self, context, layout, node, text):
+ layout.label(text=text)
+
+ def draw_color(self, context, node):
+ return (0, 1, 0, 1)
+
+
+class PovraySocketTransform(NodeSocket):
+ bl_idname = "PovraySocketTransform"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.IntProperty(min=0, max=255, default=0)
+
+ def draw(self, context, layout, node, text):
+ layout.label(text=text)
+
+ def draw_color(self, context, node):
+ return (99 / 255, 99 / 255, 199 / 255, 1)
+
+
+class PovraySocketNormal(NodeSocket):
+ bl_idname = "PovraySocketNormal"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.IntProperty(min=0, max=255, default=0)
+
+ def draw(self, context, layout, node, text):
+ layout.label(text=text)
+
+ def draw_color(self, context, node):
+ return (0.65, 0.65, 0.65, 1)
+
+
+class PovraySocketSlope(NodeSocket):
+ bl_idname = "PovraySocketSlope"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.FloatProperty(min=0.0, max=1.0)
+ height: bpy.props.FloatProperty(min=0.0, max=10.0)
+ slope: bpy.props.FloatProperty(min=-10.0, max=10.0)
+
+ def draw(self, context, layout, node, text):
+ if self.is_output or self.is_linked:
+ layout.label(text=text)
+ else:
+ layout.prop(self, "default_value", text="")
+ layout.prop(self, "height", text="")
+ layout.prop(self, "slope", text="")
+
+ def draw_color(self, context, node):
+ return (0, 0, 0, 1)
+
+
+class PovraySocketMap(NodeSocket):
+ bl_idname = "PovraySocketMap"
+ bl_label = "Povray Socket"
+ default_value: bpy.props.StringProperty()
+
+ def draw(self, context, layout, node, text):
+ layout.label(text=text)
+
+ def draw_color(self, context, node):
+ return (0.2, 0, 0.2, 1)
+
+
+class PovrayShaderNodeCategory(NodeCategory):
+ @classmethod
+ def poll(cls, context):
+ return context.space_data.tree_type == "ObjectNodeTree"
+
+
+class PovrayTextureNodeCategory(NodeCategory):
+ @classmethod
+ def poll(cls, context):
+ return context.space_data.tree_type == "TextureNodeTree"
+
+
+class PovraySceneNodeCategory(NodeCategory):
+ @classmethod
+ def poll(cls, context):
+ return context.space_data.tree_type == "CompositorNodeTree"
+
+
+node_categories = [
+ PovrayShaderNodeCategory("SHADEROUTPUT", "Output", items=[NodeItem("PovrayOutputNode")]),
+ PovrayShaderNodeCategory("SIMPLE", "Simple texture", items=[NodeItem("PovrayTextureNode")]),
+ PovrayShaderNodeCategory(
+ "MAPS",
+ "Maps",
+ items=[
+ NodeItem("PovrayBumpMapNode"),
+ NodeItem("PovrayColorImageNode"),
+ NodeItem("ShaderNormalMapNode"),
+ NodeItem("PovraySlopeNode"),
+ NodeItem("ShaderTextureMapNode"),
+ NodeItem("ShaderNodeValToRGB"),
+ ],
+ ),
+ PovrayShaderNodeCategory(
+ "OTHER",
+ "Other patterns",
+ items=[NodeItem("PovrayImagePatternNode"), NodeItem("ShaderPatternNode")],
+ ),
+ PovrayShaderNodeCategory("COLOR", "Color", items=[NodeItem("PovrayPigmentNode")]),
+ PovrayShaderNodeCategory(
+ "TRANSFORM",
+ "Transform",
+ items=[
+ NodeItem("PovrayMappingNode"),
+ NodeItem("PovrayMultiplyNode"),
+ NodeItem("PovrayModifierNode"),
+ NodeItem("PovrayTransformNode"),
+ NodeItem("PovrayValueNode"),
+ ],
+ ),
+ PovrayShaderNodeCategory(
+ "FINISH",
+ "Finish",
+ items=[
+ NodeItem("PovrayFinishNode"),
+ NodeItem("PovrayDiffuseNode"),
+ NodeItem("PovraySpecularNode"),
+ NodeItem("PovrayPhongNode"),
+ NodeItem("PovrayAmbientNode"),
+ NodeItem("PovrayMirrorNode"),
+ NodeItem("PovrayIridescenceNode"),
+ NodeItem("PovraySubsurfaceNode"),
+ ],
+ ),
+ PovrayShaderNodeCategory(
+ "CYCLES",
+ "Cycles",
+ items=[
+ NodeItem("ShaderNodeAddShader"),
+ NodeItem("ShaderNodeAmbientOcclusion"),
+ NodeItem("ShaderNodeAttribute"),
+ NodeItem("ShaderNodeBackground"),
+ NodeItem("ShaderNodeBlackbody"),
+ NodeItem("ShaderNodeBrightContrast"),
+ NodeItem("ShaderNodeBsdfAnisotropic"),
+ NodeItem("ShaderNodeBsdfDiffuse"),
+ NodeItem("ShaderNodeBsdfGlass"),
+ NodeItem("ShaderNodeBsdfGlossy"),
+ NodeItem("ShaderNodeBsdfHair"),
+ NodeItem("ShaderNodeBsdfRefraction"),
+ NodeItem("ShaderNodeBsdfToon"),
+ NodeItem("ShaderNodeBsdfTranslucent"),
+ NodeItem("ShaderNodeBsdfTransparent"),
+ NodeItem("ShaderNodeBsdfVelvet"),
+ NodeItem("ShaderNodeBump"),
+ NodeItem("ShaderNodeCameraData"),
+ NodeItem("ShaderNodeCombineHSV"),
+ NodeItem("ShaderNodeCombineRGB"),
+ NodeItem("ShaderNodeCombineXYZ"),
+ NodeItem("ShaderNodeEmission"),
+ NodeItem("ShaderNodeExtendedMaterial"),
+ NodeItem("ShaderNodeFresnel"),
+ NodeItem("ShaderNodeGamma"),
+ NodeItem("ShaderNodeGeometry"),
+ NodeItem("ShaderNodeGroup"),
+ NodeItem("ShaderNodeHairInfo"),
+ NodeItem("ShaderNodeHoldout"),
+ NodeItem("ShaderNodeHueSaturation"),
+ NodeItem("ShaderNodeInvert"),
+ NodeItem("ShaderNodeLampData"),
+ NodeItem("ShaderNodeLayerWeight"),
+ NodeItem("ShaderNodeLightFalloff"),
+ NodeItem("ShaderNodeLightPath"),
+ NodeItem("ShaderNodeMapping"),
+ NodeItem("ShaderNodeMaterial"),
+ NodeItem("ShaderNodeMath"),
+ NodeItem("ShaderNodeMixRGB"),
+ NodeItem("ShaderNodeMixShader"),
+ NodeItem("ShaderNodeNewGeometry"),
+ NodeItem("ShaderNodeNormal"),
+ NodeItem("ShaderNodeNormalMap"),
+ NodeItem("ShaderNodeObjectInfo"),
+ NodeItem("ShaderNodeOutput"),
+ NodeItem("ShaderNodeOutputLamp"),
+ NodeItem("ShaderNodeOutputLineStyle"),
+ NodeItem("ShaderNodeOutputMaterial"),
+ NodeItem("ShaderNodeOutputWorld"),
+ NodeItem("ShaderNodeParticleInfo"),
+ NodeItem("ShaderNodeRGB"),
+ NodeItem("ShaderNodeRGBCurve"),
+ NodeItem("ShaderNodeRGBToBW"),
+ NodeItem("ShaderNodeScript"),
+ NodeItem("ShaderNodeSeparateHSV"),
+ NodeItem("ShaderNodeSeparateRGB"),
+ NodeItem("ShaderNodeSeparateXYZ"),
+ NodeItem("ShaderNodeSqueeze"),
+ NodeItem("ShaderNodeSubsurfaceScattering"),
+ NodeItem("ShaderNodeTangent"),
+ NodeItem("ShaderNodeTexBrick"),
+ NodeItem("ShaderNodeTexChecker"),
+ NodeItem("ShaderNodeTexCoord"),
+ NodeItem("ShaderNodeTexEnvironment"),
+ NodeItem("ShaderNodeTexGradient"),
+ NodeItem("ShaderNodeTexImage"),
+ NodeItem("ShaderNodeTexMagic"),
+ NodeItem("ShaderNodeTexMusgrave"),
+ NodeItem("ShaderNodeTexNoise"),
+ NodeItem("ShaderNodeTexPointDensity"),
+ NodeItem("ShaderNodeTexSky"),
+ NodeItem("ShaderNodeTexVoronoi"),
+ NodeItem("ShaderNodeTexWave"),
+ NodeItem("ShaderNodeTexture"),
+ NodeItem("ShaderNodeUVAlongStroke"),
+ NodeItem("ShaderNodeUVMap"),
+ NodeItem("ShaderNodeValToRGB"),
+ NodeItem("ShaderNodeValue"),
+ NodeItem("ShaderNodeVectorCurve"),
+ NodeItem("ShaderNodeVectorMath"),
+ NodeItem("ShaderNodeVectorTransform"),
+ NodeItem("ShaderNodeVolumeAbsorption"),
+ NodeItem("ShaderNodeVolumeScatter"),
+ NodeItem("ShaderNodeWavelength"),
+ NodeItem("ShaderNodeWireframe"),
+ ],
+ ),
+ PovrayTextureNodeCategory(
+ "TEXTUREOUTPUT",
+ "Output",
+ items=[NodeItem("TextureNodeValToRGB"), NodeItem("TextureOutputNode")],
+ ),
+ PovraySceneNodeCategory("ISOSURFACE", "Isosurface", items=[NodeItem("IsoPropsNode")]),
+ PovraySceneNodeCategory("FOG", "Fog", items=[NodeItem("PovrayFogNode")]),
+]
+############### end nodes init
+############### nodes ui
+##############Nodes
+
+# def find_node_input(node, name):
+# for input in node.inputs:
+# if input.name == name:
+# return input
+
+# def panel_node_draw(layout, id_data, output_type, input_name):
+# if not id_data.use_nodes:
+# #layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
+# #layout.operator("pov.use_shading_nodes", icon='NODETREE')
+# layout.operator("WM_OT_context_toggle", icon='NODETREE').data_path = \
+# "material.pov.material_use_nodes"
+# return False
+
+# ntree = id_data.node_tree
+
+# node = find_node(id_data, output_type)
+# if not node:
+# layout.label(text="No output node")
+# else:
+# input = find_node_input(node, input_name)
+# layout.template_node_view(ntree, node, input)
+
+# return True
+
+
+class NODE_MT_POV_map_create(Menu):
+ """Create maps"""
+
+ bl_idname = "POVRAY_MT_node_map_create"
+ bl_label = "Create map"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator("node.map_create")
+
+
+def menu_func_nodes(self, context):
+ ob = context.object
+ if hasattr(ob, 'active_material'):
+ mat = context.object.active_material
+ if mat and context.space_data.tree_type == 'ObjectNodeTree':
+ self.layout.prop(mat.pov, "material_use_nodes")
+ self.layout.menu(NODE_MT_POV_map_create.bl_idname)
+ self.layout.operator("wm.updatepreviewkey")
+ if hasattr(mat, 'active_texture') and context.scene.render.engine == 'POVRAY_RENDER':
+ tex = mat.active_texture
+ if tex and context.space_data.tree_type == 'TextureNodeTree':
+ self.layout.prop(tex.pov, "texture_use_nodes")
+
+
+############### object
+
+
+class ObjectNodeTree(bpy.types.NodeTree):
+ '''Povray Material Nodes'''
+
+ bl_idname = 'ObjectNodeTree'
+ bl_label = 'Povray Object Nodes'
+ bl_icon = 'PLUGIN'
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene.render.engine == 'POVRAY_RENDER'
+
+ @classmethod
+ def get_from_context(cls, context):
+ ob = context.active_object
+ if ob and ob.type not in {'LIGHT'}:
+ ma = ob.active_material
+ if ma is not None:
+ nt_name = ma.node_tree
+ if nt_name != '':
+ return nt_name, ma, ma
+ return (None, None, None)
+
+ def update(self):
+ self.refresh = True
+
+
+################### output #############################################################################################
+
+
+class PovrayOutputNode(Node, ObjectNodeTree):
+ '''Output'''
+
+ bl_idname = 'PovrayOutputNode'
+ bl_label = 'Output'
+ bl_icon = 'SHADING_TEXTURE'
+
+ def init(self, context):
+
+ self.inputs.new('PovraySocketTexture', "Texture")
+
+ def draw_buttons(self, context, layout):
+
+ ob = context.object
+ layout.prop(ob.pov, "object_ior", slider=True)
+
+ def draw_buttons_ext(self, context, layout):
+
+ ob = context.object
+ layout.prop(ob.pov, "object_ior", slider=True)
+
+ def draw_label(self):
+ return "Output"
+
+
+################### material ###########################################################################################
+class PovrayTextureNode(Node, ObjectNodeTree):
+ '''Texture'''
+
+ bl_idname = 'PovrayTextureNode'
+ bl_label = 'Simple texture'
+ bl_icon = 'SHADING_TEXTURE'
+
+ def init(self, context):
+
+ color = self.inputs.new('PovraySocketColor', "Pigment")
+ color.default_value = (1, 1, 1)
+ normal = self.inputs.new('NodeSocketFloat', "Normal")
+ normal.hide_value = True
+ finish = self.inputs.new('NodeSocketVector', "Finish")
+ finish.hide_value = True
+
+ self.outputs.new('PovraySocketTexture', "Texture")
+
+ def draw_label(self):
+ return "Simple texture"
+
+
+class PovrayFinishNode(Node, ObjectNodeTree):
+ '''Finish'''
+
+ bl_idname = 'PovrayFinishNode'
+ bl_label = 'Finish'
+ bl_icon = 'SHADING_TEXTURE'
+
+ def init(self, context):
+
+ self.inputs.new('PovraySocketFloat_0_1', "Emission")
+ ambient = self.inputs.new('NodeSocketVector', "Ambient")
+ ambient.hide_value = True
+ diffuse = self.inputs.new('NodeSocketVector', "Diffuse")
+ diffuse.hide_value = True
+ specular = self.inputs.new('NodeSocketVector', "Highlight")
+ specular.hide_value = True
+ mirror = self.inputs.new('NodeSocketVector', "Mirror")
+ mirror.hide_value = True
+ iridescence = self.inputs.new('NodeSocketVector', "Iridescence")
+ iridescence.hide_value = True
+ subsurface = self.inputs.new('NodeSocketVector', "Translucency")
+ subsurface.hide_value = True
+ self.outputs.new('NodeSocketVector', "Finish")
+
+ def draw_label(self):
+ return "Finish"
+
+
+class PovrayDiffuseNode(Node, ObjectNodeTree):
+ '''Diffuse'''
+
+ bl_idname = 'PovrayDiffuseNode'
+ bl_label = 'Diffuse'
+ bl_icon = 'MATSPHERE'
+
+ def init(self, context):
+
+ intensity = self.inputs.new('PovraySocketFloat_0_1', "Intensity")
+ intensity.default_value = 0.8
+ albedo = self.inputs.new('NodeSocketBool', "Albedo")
+ albedo.default_value = False
+ brilliance = self.inputs.new('PovraySocketFloat_0_10', "Brilliance")
+ brilliance.default_value = 1.8
+ self.inputs.new('PovraySocketFloat_0_1', "Crand")
+ self.outputs.new('NodeSocketVector', "Diffuse")
+
+ def draw_label(self):
+ return "Diffuse"
+
+
+class PovrayPhongNode(Node, ObjectNodeTree):
+ '''Phong'''
+
+ bl_idname = 'PovrayPhongNode'
+ bl_label = 'Phong'
+ bl_icon = 'MESH_UVSPHERE'
+
+ def init(self, context):
+
+ albedo = self.inputs.new('NodeSocketBool', "Albedo")
+ intensity = self.inputs.new('PovraySocketFloat_0_1', "Intensity")
+ intensity.default_value = 0.8
+ phong_size = self.inputs.new('PovraySocketInt_0_256', "Size")
+ phong_size.default_value = 60
+ metallic = self.inputs.new('PovraySocketFloat_0_1', "Metallic")
+
+ self.outputs.new('NodeSocketVector', "Phong")
+
+ def draw_label(self):
+ return "Phong"
+
+
+class PovraySpecularNode(Node, ObjectNodeTree):
+ '''Specular'''
+
+ bl_idname = 'PovraySpecularNode'
+ bl_label = 'Specular'
+ bl_icon = 'MESH_UVSPHERE'
+
+ def init(self, context):
+
+ albedo = self.inputs.new('NodeSocketBool', "Albedo")
+ intensity = self.inputs.new('PovraySocketFloat_0_1', "Intensity")
+ intensity.default_value = 0.8
+ roughness = self.inputs.new('PovraySocketFloat_0_1', "Roughness")
+ roughness.default_value = 0.02
+ metallic = self.inputs.new('PovraySocketFloat_0_1', "Metallic")
+
+ self.outputs.new('NodeSocketVector', "Specular")
+
+ def draw_label(self):
+ return "Specular"
+
+
+class PovrayMirrorNode(Node, ObjectNodeTree):
+ '''Mirror'''
+
+ bl_idname = 'PovrayMirrorNode'
+ bl_label = 'Mirror'
+ bl_icon = 'SHADING_TEXTURE'
+
+ def init(self, context):
+
+ color = self.inputs.new('PovraySocketColor', "Color")
+ color.default_value = (1, 1, 1)
+ metallic = self.inputs.new('PovraySocketFloat_0_1', "Metallic")
+ metallic.default_value = 1.0
+ exponent = self.inputs.new('PovraySocketFloat_0_1', "Exponent")
+ exponent.default_value = 1.0
+ self.inputs.new('PovraySocketFloat_0_1', "Falloff")
+ self.inputs.new('NodeSocketBool', "Fresnel")
+ self.inputs.new('NodeSocketBool', "Conserve energy")
+ self.outputs.new('NodeSocketVector', "Mirror")
+
+ def draw_label(self):
+ return "Mirror"
+
+
+class PovrayAmbientNode(Node, ObjectNodeTree):
+ '''Ambient'''
+
+ bl_idname = 'PovrayAmbientNode'
+ bl_label = 'Ambient'
+ bl_icon = 'SHADING_SOLID'
+
+ def init(self, context):
+
+ self.inputs.new('PovraySocketColor', "Ambient")
+
+ self.outputs.new('NodeSocketVector', "Ambient")
+
+ def draw_label(self):
+ return "Ambient"
+
+
+class PovrayIridescenceNode(Node, ObjectNodeTree):
+ '''Iridescence'''
+
+ bl_idname = 'PovrayIridescenceNode'
+ bl_label = 'Iridescence'
+ bl_icon = 'MESH_UVSPHERE'
+
+ def init(self, context):
+
+ amount = self.inputs.new('NodeSocketFloat', "Amount")
+ amount.default_value = 0.25
+ thickness = self.inputs.new('NodeSocketFloat', "Thickness")
+ thickness.default_value = 1
+ self.inputs.new('NodeSocketFloat', "Turbulence")
+
+ self.outputs.new('NodeSocketVector', "Iridescence")
+
+ def draw_label(self):
+ return "Iridescence"
+
+
+class PovraySubsurfaceNode(Node, ObjectNodeTree):
+ '''Subsurface'''
+
+ bl_idname = 'PovraySubsurfaceNode'
+ bl_label = 'Subsurface'
+ bl_icon = 'MESH_UVSPHERE'
+
+ def init(self, context):
+
+ translucency = self.inputs.new('NodeSocketColor', "Translucency")
+ translucency.default_value = (0, 0, 0, 1)
+ energy = self.inputs.new('PovraySocketInt_0_256', "Energy")
+ energy.default_value = 20
+ self.outputs.new('NodeSocketVector', "Translucency")
+
+ def draw_buttons(self, context, layout):
+ scene = context.scene
+ layout.prop(scene.pov, "sslt_enable", text="SSLT")
+
+ def draw_buttons_ext(self, context, layout):
+ scene = context.scene
+ layout.prop(scene.pov, "sslt_enable", text="SSLT")
+
+ def draw_label(self):
+ return "Subsurface"
+
+
+#####################################################################################################
+
+
+class PovrayMappingNode(Node, ObjectNodeTree):
+ '''Mapping'''
+
+ bl_idname = 'PovrayMappingNode'
+ bl_label = 'Mapping'
+ bl_icon = 'NODE_TEXTURE'
+
+ warp_type: EnumProperty(
+ name="Warp Types",
+ description="Select the type of warp",
+ items=(
+ ('cubic', "Cubic", ""),
+ ('cylindrical', "Cylindrical", ""),
+ ('planar', "Planar", ""),
+ ('spherical', "Spherical", ""),
+ ('toroidal', "Toroidal", ""),
+ ('uv_mapping', "UV", ""),
+ ('NONE', "None", "No indentation"),
+ ),
+ default='NONE',
+ )
+
+ warp_orientation: EnumProperty(
+ name="Warp Orientation",
+ description="Select the orientation of warp",
+ items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")),
+ default='y',
+ )
+
+ warp_dist_exp: FloatProperty(
+ name="Distance exponent", description="Distance exponent", min=0.0, max=100.0, default=1.0
+ )
+
+ warp_tor_major_radius: FloatProperty(
+ name="Major radius",
+ description="Torus is distance from major radius",
+ min=0.0,
+ max=5.0,
+ default=1.0,
+ )
+
+ def init(self, context):
+ self.outputs.new('NodeSocketVector', "Mapping")
+
+ def draw_buttons(self, context, layout):
+
+ column = layout.column()
+ column.prop(self, "warp_type", text="Warp type")
+ if self.warp_type in {'toroidal', 'spherical', 'cylindrical', 'planar'}:
+ column.prop(self, "warp_orientation", text="Orientation")
+ column.prop(self, "warp_dist_exp", text="Exponent")
+ if self.warp_type == 'toroidal':
+ column.prop(self, "warp_tor_major_radius", text="Major R")
+
+ def draw_buttons_ext(self, context, layout):
+
+ column = layout.column()
+ column.prop(self, "warp_type", text="Warp type")
+ if self.warp_type in {'toroidal', 'spherical', 'cylindrical', 'planar'}:
+ column.prop(self, "warp_orientation", text="Orientation")
+ column.prop(self, "warp_dist_exp", text="Exponent")
+ if self.warp_type == 'toroidal':
+ column.prop(self, "warp_tor_major_radius", text="Major R")
+
+ def draw_label(self):
+ return "Mapping"
+
+
+class PovrayMultiplyNode(Node, ObjectNodeTree):
+ '''Multiply'''
+
+ bl_idname = 'PovrayMultiplyNode'
+ bl_label = 'Multiply'
+ bl_icon = 'SHADING_SOLID'
+
+ amount_x: FloatProperty(
+ name="X", description="Number of repeats", min=1.0, max=10000.0, default=1.0
+ )
+
+ amount_y: FloatProperty(
+ name="Y", description="Number of repeats", min=1.0, max=10000.0, default=1.0
+ )
+
+ amount_z: FloatProperty(
+ name="Z", description="Number of repeats", min=1.0, max=10000.0, default=1.0
+ )
+
+ def init(self, context):
+ self.outputs.new('NodeSocketVector', "Amount")
+
+ def draw_buttons(self, context, layout):
+
+ column = layout.column()
+ column.label(text="Amount")
+ row = column.row(align=True)
+ row.prop(self, "amount_x")
+ row.prop(self, "amount_y")
+ row.prop(self, "amount_z")
+
+ def draw_buttons_ext(self, context, layout):
+
+ column = layout.column()
+ column.label(text="Amount")
+ row = column.row(align=True)
+ row.prop(self, "amount_x")
+ row.prop(self, "amount_y")
+ row.prop(self, "amount_z")
+
+ def draw_label(self):
+ return "Multiply"
+
+
+class PovrayTransformNode(Node, ObjectNodeTree):
+ '''Transform'''
+
+ bl_idname = 'PovrayTransformNode'
+ bl_label = 'Transform'
+ bl_icon = 'NODE_TEXTURE'
+
+ def init(self, context):
+
+ self.inputs.new('PovraySocketFloatUnlimited', "Translate x")
+ self.inputs.new('PovraySocketFloatUnlimited', "Translate y")
+ self.inputs.new('PovraySocketFloatUnlimited', "Translate z")
+ self.inputs.new('PovraySocketFloatUnlimited', "Rotate x")
+ self.inputs.new('PovraySocketFloatUnlimited', "Rotate y")
+ self.inputs.new('PovraySocketFloatUnlimited', "Rotate z")
+ sX = self.inputs.new('PovraySocketFloatUnlimited', "Scale x")
+ sX.default_value = 1.0
+ sY = self.inputs.new('PovraySocketFloatUnlimited', "Scale y")
+ sY.default_value = 1.0
+ sZ = self.inputs.new('PovraySocketFloatUnlimited', "Scale z")
+ sZ.default_value = 1.0
+
+ self.outputs.new('NodeSocketVector', "Transform")
+
+ def draw_label(self):
+ return "Transform"
+
+
+class PovrayValueNode(Node, ObjectNodeTree):
+ '''Value'''
+
+ bl_idname = 'PovrayValueNode'
+ bl_label = 'Value'
+ bl_icon = 'SHADING_SOLID'
+
+ def init(self, context):
+
+ self.outputs.new('PovraySocketUniversal', "Value")
+
+ def draw_label(self):
+ return "Value"
+
+
+class PovrayModifierNode(Node, ObjectNodeTree):
+ '''Modifier'''
+
+ bl_idname = 'PovrayModifierNode'
+ bl_label = 'Modifier'
+ bl_icon = 'NODE_TEXTURE'
+
+ def init(self, context):
+
+ turb_x = self.inputs.new('PovraySocketFloat_0_10', "Turb X")
+ turb_x.default_value = 0.1
+ turb_y = self.inputs.new('PovraySocketFloat_0_10', "Turb Y")
+ turb_y.default_value = 0.1
+ turb_z = self.inputs.new('PovraySocketFloat_0_10', "Turb Z")
+ turb_z.default_value = 0.1
+ octaves = self.inputs.new('PovraySocketInt_1_9', "Octaves")
+ octaves.default_value = 1
+ lambat = self.inputs.new('PovraySocketFloat_0_10', "Lambda")
+ lambat.default_value = 2.0
+ omega = self.inputs.new('PovraySocketFloat_0_10', "Omega")
+ omega.default_value = 0.5
+ freq = self.inputs.new('PovraySocketFloat_0_10', "Frequency")
+ freq.default_value = 2.0
+ self.inputs.new('PovraySocketFloat_0_10', "Phase")
+
+ self.outputs.new('NodeSocketVector', "Modifier")
+
+ def draw_label(self):
+ return "Modifier"
+
+
+class PovrayPigmentNode(Node, ObjectNodeTree):
+ '''Pigment'''
+
+ bl_idname = 'PovrayPigmentNode'
+ bl_label = 'Color'
+ bl_icon = 'SHADING_SOLID'
+
+ def init(self, context):
+
+ color = self.inputs.new('PovraySocketColor', "Color")
+ color.default_value = (1, 1, 1)
+ pov_filter = self.inputs.new('PovraySocketFloat_0_1', "Filter")
+ transmit = self.inputs.new('PovraySocketFloat_0_1', "Transmit")
+ self.outputs.new('NodeSocketColor', "Pigment")
+
+ def draw_label(self):
+ return "Color"
+
+
+class PovrayColorImageNode(Node, ObjectNodeTree):
+ '''ColorImage'''
+
+ bl_idname = 'PovrayColorImageNode'
+ bl_label = 'Image map'
+
+ map_type: bpy.props.EnumProperty(
+ name="Map type",
+ description="",
+ items=(
+ ('uv_mapping', "UV", ""),
+ ('0', "Planar", "Default planar mapping"),
+ ('1', "Spherical", "Spherical mapping"),
+ ('2', "Cylindrical", "Cylindrical mapping"),
+ ('5', "Torroidal", "Torus or donut shaped mapping"),
+ ),
+ default='0',
+ )
+ image: StringProperty(maxlen=1024) # , subtype="FILE_PATH"
+ interpolate: EnumProperty(
+ name="Interpolate",
+ description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
+ items=(
+ ('2', "Bilinear", "Gives bilinear interpolation"),
+ ('4', "Normalized", "Gives normalized distance"),
+ ),
+ default='2',
+ )
+ premultiplied: BoolProperty(default=False)
+ once: BoolProperty(description="Not to repeat", default=False)
+
+ def init(self, context):
+
+ gamma = self.inputs.new('PovraySocketFloat_000001_10', "Gamma")
+ gamma.default_value = 2.0
+ transmit = self.inputs.new('PovraySocketFloat_0_1', "Transmit")
+ pov_filter = self.inputs.new('PovraySocketFloat_0_1', "Filter")
+ mapping = self.inputs.new('NodeSocketVector', "Mapping")
+ mapping.hide_value = True
+ transform = self.inputs.new('NodeSocketVector', "Transform")
+ transform.hide_value = True
+ modifier = self.inputs.new('NodeSocketVector', "Modifier")
+ modifier.hide_value = True
+
+ self.outputs.new('NodeSocketColor', "Pigment")
+
+ def draw_buttons(self, context, layout):
+
+ column = layout.column()
+ im = None
+ for image in bpy.data.images:
+ if image.name == self.image:
+ im = image
+ split = column.split(factor=0.8, align=True)
+ split.prop_search(self, "image", context.blend_data, "images", text="")
+ split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+ if im is not None:
+ column.prop(im, "source", text="")
+ column.prop(self, "map_type", text="")
+ column.prop(self, "interpolate", text="")
+ row = column.row()
+ row.prop(self, "premultiplied", text="Premul")
+ row.prop(self, "once", text="Once")
+
+ def draw_buttons_ext(self, context, layout):
+
+ column = layout.column()
+ im = None
+ for image in bpy.data.images:
+ if image.name == self.image:
+ im = image
+ split = column.split(factor=0.8, align=True)
+ split.prop_search(self, "image", context.blend_data, "images", text="")
+ split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+ if im is not None:
+ column.prop(im, "source", text="")
+ column.prop(self, "map_type", text="")
+ column.prop(self, "interpolate", text="")
+ row = column.row()
+ row.prop(self, "premultiplied", text="Premul")
+ row.prop(self, "once", text="Once")
+
+ def draw_label(self):
+ return "Image map"
+
+
+class PovrayBumpMapNode(Node, ObjectNodeTree):
+ '''BumpMap'''
+
+ bl_idname = 'PovrayBumpMapNode'
+ bl_label = 'Bump map'
+ bl_icon = 'TEXTURE'
+
+ map_type: bpy.props.EnumProperty(
+ name="Map type",
+ description="",
+ items=(
+ ('uv_mapping', "UV", ""),
+ ('0', "Planar", "Default planar mapping"),
+ ('1', "Spherical", "Spherical mapping"),
+ ('2', "Cylindrical", "Cylindrical mapping"),
+ ('5', "Torroidal", "Torus or donut shaped mapping"),
+ ),
+ default='0',
+ )
+ image: StringProperty(maxlen=1024) # , subtype="FILE_PATH"
+ interpolate: EnumProperty(
+ name="Interpolate",
+ description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
+ items=(
+ ('2', "Bilinear", "Gives bilinear interpolation"),
+ ('4', "Normalized", "Gives normalized distance"),
+ ),
+ default='2',
+ )
+ once: BoolProperty(description="Not to repeat", default=False)
+
+ def init(self, context):
+
+ self.inputs.new('PovraySocketFloat_0_10', "Normal")
+ mapping = self.inputs.new('NodeSocketVector', "Mapping")
+ mapping.hide_value = True
+ transform = self.inputs.new('NodeSocketVector', "Transform")
+ transform.hide_value = True
+ modifier = self.inputs.new('NodeSocketVector', "Modifier")
+ modifier.hide_value = True
+
+ normal = self.outputs.new('NodeSocketFloat', "Normal")
+ normal.hide_value = True
+
+ def draw_buttons(self, context, layout):
+
+ column = layout.column()
+ im = None
+ for image in bpy.data.images:
+ if image.name == self.image:
+ im = image
+ split = column.split(factor=0.8, align=True)
+ split.prop_search(self, "image", context.blend_data, "images", text="")
+ split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+ if im is not None:
+ column.prop(im, "source", text="")
+ column.prop(self, "map_type", text="")
+ column.prop(self, "interpolate", text="")
+ column.prop(self, "once", text="Once")
+
+ def draw_buttons_ext(self, context, layout):
+
+ column = layout.column()
+ im = None
+ for image in bpy.data.images:
+ if image.name == self.image:
+ im = image
+ split = column.split(factor=0.8, align=True)
+ split.prop_search(self, "image", context.blend_data, "images", text="")
+ split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+ if im is not None:
+ column.prop(im, "source", text="")
+ column.prop(self, "map_type", text="")
+ column.prop(self, "interpolate", text="")
+ column.prop(self, "once", text="Once")
+
+ def draw_label(self):
+ return "Bump Map"
+
+
+class PovrayImagePatternNode(Node, ObjectNodeTree):
+ '''ImagePattern'''
+
+ bl_idname = 'PovrayImagePatternNode'
+ bl_label = 'Image pattern'
+ bl_icon = 'NODE_TEXTURE'
+
+ map_type: bpy.props.EnumProperty(
+ name="Map type",
+ description="",
+ items=(
+ ('uv_mapping', "UV", ""),
+ ('0', "Planar", "Default planar mapping"),
+ ('1', "Spherical", "Spherical mapping"),
+ ('2', "Cylindrical", "Cylindrical mapping"),
+ ('5', "Torroidal", "Torus or donut shaped mapping"),
+ ),
+ default='0',
+ )
+ image: StringProperty(maxlen=1024) # , subtype="FILE_PATH"
+ interpolate: EnumProperty(
+ name="Interpolate",
+ description="Adding the interpolate keyword can smooth the jagged look of a bitmap",
+ items=(
+ ('2', "Bilinear", "Gives bilinear interpolation"),
+ ('4', "Normalized", "Gives normalized distance"),
+ ),
+ default='2',
+ )
+ premultiplied: BoolProperty(default=False)
+ once: BoolProperty(description="Not to repeat", default=False)
+ use_alpha: BoolProperty(default=True)
+
+ def init(self, context):
+
+ gamma = self.inputs.new('PovraySocketFloat_000001_10', "Gamma")
+ gamma.default_value = 2.0
+
+ self.outputs.new('PovraySocketPattern', "Pattern")
+
+ def draw_buttons(self, context, layout):
+
+ column = layout.column()
+ im = None
+ for image in bpy.data.images:
+ if image.name == self.image:
+ im = image
+ split = column.split(factor=0.8, align=True)
+ split.prop_search(self, "image", context.blend_data, "images", text="")
+ split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+ if im is not None:
+ column.prop(im, "source", text="")
+ column.prop(self, "map_type", text="")
+ column.prop(self, "interpolate", text="")
+ row = column.row()
+ row.prop(self, "premultiplied", text="Premul")
+ row.prop(self, "once", text="Once")
+ column.prop(self, "use_alpha", text="Use alpha")
+
+ def draw_buttons_ext(self, context, layout):
+
+ column = layout.column()
+ im = None
+ for image in bpy.data.images:
+ if image.name == self.image:
+ im = image
+ split = column.split(factor=0.8, align=True)
+ split.prop_search(self, "image", context.blend_data, "images", text="")
+ split.operator("pov.imageopen", text="", icon="FILEBROWSER")
+ if im is not None:
+ column.prop(im, "source", text="")
+ column.prop(self, "map_type", text="")
+ column.prop(self, "interpolate", text="")
+ row = column.row()
+ row.prop(self, "premultiplied", text="Premul")
+ row.prop(self, "once", text="Once")
+
+ def draw_label(self):
+ return "Image pattern"
+
+
+class ShaderPatternNode(Node, ObjectNodeTree):
+ '''Pattern'''
+
+ bl_idname = 'ShaderPatternNode'
+ bl_label = 'Other patterns'
+
+ pattern: EnumProperty(
+ name="Pattern",
+ description="Agate, Crackle, Gradient, Pavement, Spiral, Tiling",
+ items=(
+ ('agate', "Agate", ""),
+ ('crackle', "Crackle", ""),
+ ('gradient', "Gradient", ""),
+ ('pavement', "Pavement", ""),
+ ('spiral1', "Spiral 1", ""),
+ ('spiral2', "Spiral 2", ""),
+ ('tiling', "Tiling", ""),
+ ),
+ default='agate',
+ )
+
+ agate_turb: FloatProperty(
+ name="Agate turb", description="Agate turbulence", min=0.0, max=100.0, default=0.5
+ )
+
+ crackle_form_x: FloatProperty(
+ name="X", description="Form vector X", min=-150.0, max=150.0, default=-1
+ )
+
+ crackle_form_y: FloatProperty(
+ name="Y", description="Form vector Y", min=-150.0, max=150.0, default=1
+ )
+
+ crackle_form_z: FloatProperty(
+ name="Z", description="Form vector Z", min=-150.0, max=150.0, default=0
+ )
+
+ crackle_metric: FloatProperty(
+ name="Metric", description="Crackle metric", min=0.0, max=150.0, default=1
+ )
+
+ crackle_solid: BoolProperty(name="Solid", description="Crackle solid", default=False)
+
+ spiral_arms: FloatProperty(name="Number", description="", min=0.0, max=256.0, default=2.0)
+
+ tiling_number: IntProperty(name="Number", description="", min=1, max=27, default=1)
+
+ gradient_orient: EnumProperty(
+ name="Orient",
+ description="",
+ items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")),
+ default='x',
+ )
+
+ def init(self, context):
+
+ pat = self.outputs.new('PovraySocketPattern', "Pattern")
+
+ def draw_buttons(self, context, layout):
+
+ layout.prop(self, "pattern", text="")
+ if self.pattern == 'agate':
+ layout.prop(self, "agate_turb")
+ if self.pattern == 'crackle':
+ layout.prop(self, "crackle_metric")
+ layout.prop(self, "crackle_solid")
+ layout.label(text="Form:")
+ layout.prop(self, "crackle_form_x")
+ layout.prop(self, "crackle_form_y")
+ layout.prop(self, "crackle_form_z")
+ if self.pattern in {"spiral1", "spiral2"}:
+ layout.prop(self, "spiral_arms")
+ if self.pattern in {'tiling'}:
+ layout.prop(self, "tiling_number")
+ if self.pattern in {'gradient'}:
+ layout.prop(self, "gradient_orient")
+
+ def draw_buttons_ext(self, context, layout):
+ pass
+
+ def draw_label(self):
+ return "Other patterns"
+
+
+class ShaderTextureMapNode(Node, ObjectNodeTree):
+ '''Texture Map'''
+
+ bl_idname = 'ShaderTextureMapNode'
+ bl_label = 'Texture map'
+
+ brick_size_x: FloatProperty(name="X", description="", min=0.0000, max=1.0000, default=0.2500)
+
+ brick_size_y: FloatProperty(name="Y", description="", min=0.0000, max=1.0000, default=0.0525)
+
+ brick_size_z: FloatProperty(name="Z", description="", min=0.0000, max=1.0000, default=0.1250)
+
+ brick_mortar: FloatProperty(
+ name="Mortar", description="Mortar", min=0.000, max=1.500, default=0.01
+ )
+
+ def init(self, context):
+ mat = bpy.context.object.active_material
+ self.inputs.new('PovraySocketPattern', "")
+ color = self.inputs.new('NodeSocketColor', "Color ramp")
+ color.hide_value = True
+ for i in range(0, 4):
+ transform = self.inputs.new('PovraySocketTransform', "Transform")
+ transform.hide_value = True
+ number = mat.pov.inputs_number
+ for i in range(number):
+ self.inputs.new('PovraySocketTexture', "%s" % i)
+
+ self.outputs.new('PovraySocketTexture', "Texture")
+
+ def draw_buttons(self, context, layout):
+
+ if self.inputs[0].default_value == 'brick':
+ layout.prop(self, "brick_mortar")
+ layout.label(text="Brick size:")
+ layout.prop(self, "brick_size_x")
+ layout.prop(self, "brick_size_y")
+ layout.prop(self, "brick_size_z")
+
+ def draw_buttons_ext(self, context, layout):
+
+ if self.inputs[0].default_value == 'brick':
+ layout.prop(self, "brick_mortar")
+ layout.label(text="Brick size:")
+ layout.prop(self, "brick_size_x")
+ layout.prop(self, "brick_size_y")
+ layout.prop(self, "brick_size_z")
+
+ def draw_label(self):
+ return "Texture map"
+
+
+class ShaderNormalMapNode(Node, ObjectNodeTree):
+ '''Normal Map'''
+
+ bl_idname = 'ShaderNormalMapNode'
+ bl_label = 'Normal map'
+
+ brick_size_x: FloatProperty(name="X", description="", min=0.0000, max=1.0000, default=0.2500)
+
+ brick_size_y: FloatProperty(name="Y", description="", min=0.0000, max=1.0000, default=0.0525)
+
+ brick_size_z: FloatProperty(name="Z", description="", min=0.0000, max=1.0000, default=0.1250)
+
+ brick_mortar: FloatProperty(
+ name="Mortar", description="Mortar", min=0.000, max=1.500, default=0.01
+ )
+
+ def init(self, context):
+ self.inputs.new('PovraySocketPattern', "")
+ normal = self.inputs.new('PovraySocketFloat_10', "Normal")
+ slope = self.inputs.new('PovraySocketMap', "Slope map")
+ for i in range(0, 4):
+ transform = self.inputs.new('PovraySocketTransform', "Transform")
+ transform.hide_value = True
+ self.outputs.new('PovraySocketNormal', "Normal")
+
+ def draw_buttons(self, context, layout):
+ # for i, inp in enumerate(self.inputs):
+
+ if self.inputs[0].default_value == 'brick':
+ layout.prop(self, "brick_mortar")
+ layout.label(text="Brick size:")
+ layout.prop(self, "brick_size_x")
+ layout.prop(self, "brick_size_y")
+ layout.prop(self, "brick_size_z")
+
+ def draw_buttons_ext(self, context, layout):
+
+ if self.inputs[0].default_value == 'brick':
+ layout.prop(self, "brick_mortar")
+ layout.label(text="Brick size:")
+ layout.prop(self, "brick_size_x")
+ layout.prop(self, "brick_size_y")
+ layout.prop(self, "brick_size_z")
+
+ def draw_label(self):
+ return "Normal map"
+
+
+class ShaderNormalMapEntryNode(Node, ObjectNodeTree):
+ '''Normal Map Entry'''
+
+ bl_idname = 'ShaderNormalMapEntryNode'
+ bl_label = 'Normal map entry'
+
+ def init(self, context):
+ self.inputs.new('PovraySocketFloat_0_1', "Stop")
+ self.inputs.new('PovraySocketFloat_0_1', "Gray")
+
+ def draw_label(self):
+ return "Normal map entry"
+
+
+class IsoPropsNode(Node, CompositorNodeTree):
+ '''ISO Props'''
+
+ bl_idname = 'IsoPropsNode'
+ bl_label = 'Iso'
+ node_label: StringProperty(maxlen=1024)
+
+ def init(self, context):
+ ob = bpy.context.object
+ self.node_label = ob.name
+ text_name = ob.pov.function_text
+ if text_name:
+ text = bpy.data.texts[text_name]
+ for line in text.lines:
+ split = line.body.split()
+ if split[0] == "#declare":
+ socket = self.inputs.new('NodeSocketFloat', "%s" % split[1])
+ value = split[3].split(";")
+ value = value[0]
+ socket.default_value = float(value)
+
+ def draw_label(self):
+ return self.node_label
+
+
+class PovrayFogNode(Node, CompositorNodeTree):
+ '''Fog settings'''
+
+ bl_idname = 'PovrayFogNode'
+ bl_label = 'Fog'
+
+ def init(self, context):
+ color = self.inputs.new('NodeSocketColor', "Color")
+ color.default_value = (0.7, 0.7, 0.7, 0.25)
+ self.inputs.new('PovraySocketFloat_0_1', "Filter")
+ distance = self.inputs.new('NodeSocketInt', "Distance")
+ distance.default_value = 150
+ self.inputs.new('NodeSocketBool', "Ground")
+ fog_offset = self.inputs.new('NodeSocketFloat', "Offset")
+ fog_alt = self.inputs.new('NodeSocketFloat', "Altitude")
+ turb = self.inputs.new('NodeSocketVector', "Turbulence")
+ turb_depth = self.inputs.new('PovraySocketFloat_0_10', "Depth")
+ turb_depth.default_value = 0.5
+ octaves = self.inputs.new('PovraySocketInt_1_9', "Octaves")
+ octaves.default_value = 5
+ lambdat = self.inputs.new('PovraySocketFloat_0_10', "Lambda")
+ lambdat.default_value = 1.25
+ omega = self.inputs.new('PovraySocketFloat_0_10', "Omega")
+ omega.default_value = 0.35
+ translate = self.inputs.new('NodeSocketVector', "Translate")
+ rotate = self.inputs.new('NodeSocketVector', "Rotate")
+ scale = self.inputs.new('NodeSocketVector', "Scale")
+ scale.default_value = (1, 1, 1)
+
+ def draw_label(self):
+ return "Fog"
+
+
+class PovraySlopeNode(Node, TextureNodeTree):
+ '''Output'''
+
+ bl_idname = 'PovraySlopeNode'
+ bl_label = 'Slope Map'
+
+ def init(self, context):
+ self.use_custom_color = True
+ self.color = (0, 0.2, 0)
+ slope = self.inputs.new('PovraySocketSlope', "0")
+ slope = self.inputs.new('PovraySocketSlope', "1")
+ slopemap = self.outputs.new('PovraySocketMap', "Slope map")
+ output.hide_value = True
+
+ def draw_buttons(self, context, layout):
+
+ layout.operator("pov.nodeinputadd")
+ row = layout.row()
+ row.label(text='Value')
+ row.label(text='Height')
+ row.label(text='Slope')
+
+ def draw_buttons_ext(self, context, layout):
+
+ layout.operator("pov.nodeinputadd")
+ row = layout.row()
+ row.label(text='Value')
+ row.label(text='Height')
+ row.label(text='Slope')
+
+ def draw_label(self):
+ return "Slope Map"
+
+
+######################################## Texture nodes ###############################
+class TextureOutputNode(Node, TextureNodeTree):
+ '''Output'''
+
+ bl_idname = 'TextureOutputNode'
+ bl_label = 'Color Map'
+
+ def init(self, context):
+ tex = bpy.context.object.active_material.active_texture
+ num_sockets = int(tex.pov.density_lines / 32)
+ for i in range(num_sockets):
+ color = self.inputs.new('NodeSocketColor', "%s" % i)
+ color.hide_value = True
+
+ def draw_buttons(self, context, layout):
+
+ layout.label(text="Color Ramps:")
+
+ def draw_label(self):
+ return "Color Map"
+
+
+##################################################################################
+#################################Operators########################################
+##################################################################################
+
+
+class NODE_OT_iso_add(Operator):
+ bl_idname = "pov.nodeisoadd"
+ bl_label = "Create iso props"
+
+ def execute(self, context):
+ ob = bpy.context.object
+ if bpy.context.scene.use_nodes == False:
+ bpy.context.scene.use_nodes = True
+ tree = bpy.context.scene.node_tree
+ for node in tree.nodes:
+ if node.bl_idname == "IsoPropsNode" and node.label == ob.name:
+ tree.nodes.remove(node)
+ isonode = tree.nodes.new('IsoPropsNode')
+ isonode.location = (0, 0)
+ isonode.label = ob.name
+ return {'FINISHED'}
+
+
+class NODE_OT_map_create(Operator):
+ bl_idname = "node.map_create"
+ bl_label = "Create map"
+
+ def execute(self, context):
+ x = y = 0
+ space = context.space_data
+ tree = space.edit_tree
+ for node in tree.nodes:
+ if node.select == True:
+ x, y = node.location
+ node.select = False
+ tmap = tree.nodes.new('ShaderTextureMapNode')
+ tmap.location = (x - 200, y)
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ wm = context.window_manager
+ return wm.invoke_props_dialog(self)
+
+ def draw(self, context):
+ layout = self.layout
+ mat = context.object.active_material
+ layout.prop(mat.pov, "inputs_number")
+
+
+class NODE_OT_povray_node_texture_map_add(Operator):
+ bl_idname = "pov.nodetexmapadd"
+ bl_label = "Texture map"
+
+ def execute(self, context):
+ tree = bpy.context.object.active_material.node_tree
+ tmap = tree.nodes.active
+ bpy.context.object.active_material.node_tree.nodes.active = tmap
+ el = tmap.color_ramp.elements.new(0.5)
+ for el in tmap.color_ramp.elements:
+ el.color = (0, 0, 0, 1)
+ for inp in tmap.inputs:
+ tmap.inputs.remove(inp)
+ for outp in tmap.outputs:
+ tmap.outputs.remove(outp)
+ pattern = tmap.inputs.new('NodeSocketVector', "Pattern")
+ pattern.hide_value = True
+ for i in range(0, 3):
+ tmap.inputs.new('NodeSocketColor', "Shader")
+ tmap.outputs.new('NodeSocketShader', "BSDF")
+ tmap.label = "Texture Map"
+ return {'FINISHED'}
+
+
+class NODE_OT_povray_node_output_add(Operator):
+ bl_idname = "pov.nodeoutputadd"
+ bl_label = "Output"
+
+ def execute(self, context):
+ tree = bpy.context.object.active_material.node_tree
+ tmap = tree.nodes.new('ShaderNodeOutputMaterial')
+ bpy.context.object.active_material.node_tree.nodes.active = tmap
+ for inp in tmap.inputs:
+ tmap.inputs.remove(inp)
+ tmap.inputs.new('NodeSocketShader', "Surface")
+ tmap.label = "Output"
+ return {'FINISHED'}
+
+
+class NODE_OT_povray_node_layered_add(Operator):
+ bl_idname = "pov.nodelayeredadd"
+ bl_label = "Layered material"
+
+ def execute(self, context):
+ tree = bpy.context.object.active_material.node_tree
+ tmap = tree.nodes.new('ShaderNodeAddShader')
+ bpy.context.object.active_material.node_tree.nodes.active = tmap
+ tmap.label = "Layered material"
+ return {'FINISHED'}
+
+
+class NODE_OT_povray_input_add(Operator):
+ bl_idname = "pov.nodeinputadd"
+ bl_label = "Add entry"
+
+ def execute(self, context):
+ node = bpy.context.object.active_material.node_tree.nodes.active
+ if node.type in {'VALTORGB'}:
+ number = 1
+ for inp in node.inputs:
+ if inp.type == 'SHADER':
+ number += 1
+ node.inputs.new('NodeSocketShader', "%s" % number)
+ els = node.color_ramp.elements
+ pos1 = els[len(els) - 1].position
+ pos2 = els[len(els) - 2].position
+ pos = (pos1 - pos2) / 2 + pos2
+ el = els.new(pos)
+
+ if node.bl_idname == 'PovraySlopeNode':
+ number = len(node.inputs)
+ node.inputs.new('PovraySocketSlope', "%s" % number)
+
+ return {'FINISHED'}
+
+
+class NODE_OT_povray_input_remove(Operator):
+ bl_idname = "pov.nodeinputremove"
+ bl_label = "Remove input"
+
+ def execute(self, context):
+ node = bpy.context.object.active_material.node_tree.nodes.active
+ if node.type in {'VALTORGB', 'ADD_SHADER'}:
+ number = len(node.inputs) - 1
+ if number > 5:
+ inp = node.inputs[number]
+ node.inputs.remove(inp)
+ if node.type in {'VALTORGB'}:
+ els = node.color_ramp.elements
+ number = len(els) - 2
+ el = els[number]
+ els.remove(el)
+ return {'FINISHED'}
+
+
+class NODE_OT_povray_image_open(Operator):
+ bl_idname = "pov.imageopen"
+ bl_label = "Open"
+
+ filepath: StringProperty(
+ name="File Path", description="Open image", maxlen=1024, subtype='FILE_PATH'
+ )
+
+ def invoke(self, context, event):
+ context.window_manager.fileselect_add(self)
+ return {'RUNNING_MODAL'}
+
+ def execute(self, context):
+ im = bpy.data.images.load(self.filepath)
+ node = context.object.active_material.node_tree.nodes.active
+ node.image = im.name
+ return {'FINISHED'}
+
+
+# class TEXTURE_OT_povray_open_image(Operator):
+# bl_idname = "pov.openimage"
+# bl_label = "Open Image"
+
+# filepath = StringProperty(
+# name="File Path",
+# description="Open image",
+# maxlen=1024,
+# subtype='FILE_PATH',
+# )
+
+# def invoke(self, context, event):
+# context.window_manager.fileselect_add(self)
+# return {'RUNNING_MODAL'}
+
+# def execute(self, context):
+# im=bpy.data.images.load(self.filepath)
+# tex = context.texture
+# tex.pov.image = im.name
+# view_layer = context.view_layer
+# view_layer.update()
+# return {'FINISHED'}
+
+
+class PovrayPatternNode(Operator):
+ bl_idname = "pov.patternnode"
+ bl_label = "Pattern"
+
+ add = True
+
+ def execute(self, context):
+ space = context.space_data
+ tree = space.edit_tree
+ for node in tree.nodes:
+ node.select = False
+ if self.add == True:
+ tmap = tree.nodes.new('ShaderNodeValToRGB')
+ tmap.label = "Pattern"
+ for inp in tmap.inputs:
+ tmap.inputs.remove(inp)
+ for outp in tmap.outputs:
+ tmap.outputs.remove(outp)
+ pattern = tmap.inputs.new('PovraySocketPattern', "Pattern")
+ pattern.hide_value = True
+ mapping = tmap.inputs.new('NodeSocketVector', "Mapping")
+ mapping.hide_value = True
+ transform = tmap.inputs.new('NodeSocketVector', "Transform")
+ transform.hide_value = True
+ modifier = tmap.inputs.new('NodeSocketVector', "Modifier")
+ modifier.hide_value = True
+ for i in range(0, 2):
+ tmap.inputs.new('NodeSocketShader', "%s" % (i + 1))
+ tmap.outputs.new('NodeSocketShader', "Material")
+ tmap.outputs.new('NodeSocketColor', "Color")
+ tree.nodes.active = tmap
+ self.add = False
+ aNode = tree.nodes.active
+ aNode.select = True
+ v2d = context.region.view2d
+ x, y = v2d.region_to_view(self.x, self.y)
+ aNode.location = (x, y)
+
+ def modal(self, context, event):
+ if event.type == 'MOUSEMOVE':
+ self.x = event.mouse_region_x
+ self.y = event.mouse_region_y
+ self.execute(context)
+ return {'RUNNING_MODAL'}
+ elif event.type == 'LEFTMOUSE':
+ return {'FINISHED'}
+ elif event.type in ('RIGHTMOUSE', 'ESC'):
+ return {'CANCELLED'}
+
+ return {'RUNNING_MODAL'}
+
+ def invoke(self, context, event):
+ context.window_manager.modal_handler_add(self)
+ return {'RUNNING_MODAL'}
+
+
+class UpdatePreviewMaterial(Operator):
+ '''Operator update preview material'''
+
+ bl_idname = "node.updatepreview"
+ bl_label = "Update preview"
+
+ def execute(self, context):
+ scene = context.view_layer
+ ob = context.object
+ for obj in scene.objects:
+ if obj != ob:
+ scene.objects.active = ob
+ break
+ scene.objects.active = ob
+
+ def modal(self, context, event):
+ if event.type == 'RIGHTMOUSE':
+ self.execute(context)
+ return {'FINISHED'}
+ return {'PASS_THROUGH'}
+
+ def invoke(self, context, event):
+ context.window_manager.modal_handler_add(self)
+ return {'RUNNING_MODAL'}
+
+
+class UpdatePreviewKey(Operator):
+ '''Operator update preview keymap'''
+
+ bl_idname = "wm.updatepreviewkey"
+ bl_label = "Activate RMB"
+
+ @classmethod
+ def poll(cls, context):
+ conf = context.window_manager.keyconfigs.active
+ mapstr = "Node Editor"
+ map = conf.keymaps[mapstr]
+ try:
+ map.keymap_items["node.updatepreview"]
+ return False
+ except BaseException as e:
+ print(e.__doc__)
+ print('An exception occurred: {}'.format(e))
+ return True
+
+ def execute(self, context):
+ conf = context.window_manager.keyconfigs.active
+ mapstr = "Node Editor"
+ map = conf.keymaps[mapstr]
+ map.keymap_items.new("node.updatepreview", type='RIGHTMOUSE', value="PRESS")
+ return {'FINISHED'}
+
+
+classes = (
+ PovraySocketUniversal,
+ PovraySocketFloat_0_1,
+ PovraySocketFloat_0_10,
+ PovraySocketFloat_10,
+ PovraySocketFloatPositive,
+ PovraySocketFloat_000001_10,
+ PovraySocketFloatUnlimited,
+ PovraySocketInt_1_9,
+ PovraySocketInt_0_256,
+ PovraySocketPattern,
+ PovraySocketColor,
+ PovraySocketColorRGBFT,
+ PovraySocketTexture,
+ PovraySocketTransform,
+ PovraySocketNormal,
+ PovraySocketSlope,
+ PovraySocketMap,
+ # PovrayShaderNodeCategory, # XXX SOMETHING BROKEN from 2.8 ?
+ # PovrayTextureNodeCategory, # XXX SOMETHING BROKEN from 2.8 ?
+ # PovraySceneNodeCategory, # XXX SOMETHING BROKEN from 2.8 ?
+ NODE_MT_POV_map_create,
+ ObjectNodeTree,
+ PovrayOutputNode,
+ PovrayTextureNode,
+ PovrayFinishNode,
+ PovrayDiffuseNode,
+ PovrayPhongNode,
+ PovraySpecularNode,
+ PovrayMirrorNode,
+ PovrayAmbientNode,
+ PovrayIridescenceNode,
+ PovraySubsurfaceNode,
+ PovrayMappingNode,
+ PovrayMultiplyNode,
+ PovrayTransformNode,
+ PovrayValueNode,
+ PovrayModifierNode,
+ PovrayPigmentNode,
+ PovrayColorImageNode,
+ PovrayBumpMapNode,
+ PovrayImagePatternNode,
+ ShaderPatternNode,
+ ShaderTextureMapNode,
+ ShaderNormalMapNode,
+ ShaderNormalMapEntryNode,
+ IsoPropsNode,
+ PovrayFogNode,
+ PovraySlopeNode,
+ TextureOutputNode,
+ NODE_OT_iso_add,
+ NODE_OT_map_create,
+ NODE_OT_povray_node_texture_map_add,
+ NODE_OT_povray_node_output_add,
+ NODE_OT_povray_node_layered_add,
+ NODE_OT_povray_input_add,
+ NODE_OT_povray_input_remove,
+ NODE_OT_povray_image_open,
+ PovrayPatternNode,
+ UpdatePreviewMaterial,
+ UpdatePreviewKey,
+)
+
+
+def register():
+ # from bpy.utils import register_class
+ bpy.types.NODE_HT_header.append(menu_func_nodes)
+ nodeitems_utils.register_node_categories("POVRAYNODES", node_categories)
+ for cls in classes:
+ register_class(cls)
+
+
+def unregister():
+ # from bpy.utils import unregister_class
+
+ for cls in reversed(classes):
+ unregister_class(cls)
+ nodeitems_utils.unregister_node_categories("POVRAYNODES")
+ bpy.types.NODE_HT_header.remove(menu_func_nodes)
diff --git a/render_povray/shading_properties.py b/render_povray/shading_properties.py
new file mode 100755
index 00000000..18895eba
--- /dev/null
+++ b/render_povray/shading_properties.py
@@ -0,0 +1,2290 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare shading properties exported to POV textures."""
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+ FloatVectorProperty,
+ StringProperty,
+ BoolProperty,
+ IntProperty,
+ FloatProperty,
+ EnumProperty,
+ PointerProperty,
+)
+
+
+def check_material(mat):
+ """Check that material node tree is not empty if use node button is on"""
+ if mat is not None:
+ if mat.use_nodes:
+ if not mat.node_tree: # FORMERLY : #mat.active_node_material is not None:
+ return True
+ return False
+ return True
+ return False
+
+
+def pov_context_tex_datablock(context):
+ """Texture context type recreated as deprecated in blender 2.8"""
+
+ idblock = context.brush
+ if idblock and context.scene.texture_context == 'OTHER':
+ return idblock
+
+ # idblock = bpy.context.active_object.active_material
+ idblock = context.view_layer.objects.active.active_material
+ if idblock and context.scene.texture_context == 'MATERIAL':
+ return idblock
+
+ idblock = context.scene.world
+ if idblock and context.scene.texture_context == 'WORLD':
+ return idblock
+
+ idblock = context.light
+ if idblock and context.scene.texture_context == 'LIGHT':
+ return idblock
+
+ if context.particle_system and context.scene.texture_context == 'PARTICLES':
+ idblock = context.particle_system.settings
+
+ return idblock
+
+ idblock = context.line_style
+ if idblock and context.scene.texture_context == 'LINESTYLE':
+ return idblock
+
+
+def active_texture_name_from_uilist(self, context):
+ """Name created texture slots the same as created texture"""
+ idblock = pov_context_tex_datablock(context)
+ # mat = context.view_layer.objects.active.active_material
+ if idblock is not None:
+ index = idblock.pov.active_texture_index
+ name = idblock.pov_texture_slots[index].name
+ newname = idblock.pov_texture_slots[index].texture
+ tex = bpy.data.textures[name]
+ tex.name = newname
+ idblock.pov_texture_slots[index].name = newname
+
+
+def active_texture_name_from_search(self, context):
+ """Texture rolldown to change the data linked by an existing texture"""
+ idblock = pov_context_tex_datablock(context)
+ # mat = context.view_layer.objects.active.active_material
+ if idblock is not None:
+ index = idblock.pov.active_texture_index
+ slot = idblock.pov_texture_slots[index]
+ name = slot.texture_search
+
+ try:
+ # tex = bpy.data.textures[name]
+ slot.name = name
+ slot.texture = name
+ # Switch paint brush to this texture so settings remain contextual
+ # bpy.context.tool_settings.image_paint.brush.texture = tex
+ # bpy.context.tool_settings.image_paint.brush.mask_texture = tex
+ except BaseException as e:
+ print(e.__doc__)
+ print('An exception occurred: {}'.format(e))
+ pass
+
+
+def brush_texture_update(self, context):
+
+ """Brush texture rolldown must show active slot texture props"""
+ idblock = pov_context_tex_datablock(context)
+ if idblock is not None:
+ # mat = context.view_layer.objects.active.active_material
+ idblock = pov_context_tex_datablock(context)
+ slot = idblock.pov_texture_slots[idblock.pov.active_texture_index]
+ tex = slot.texture
+
+ if tex:
+ # Switch paint brush to active texture so slot and settings remain contextual
+ bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
+ bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
+
+
+class RenderPovSettingsMaterial(PropertyGroup):
+ """Declare material level properties controllable in UI and translated to POV."""
+
+ ######################Begin Old Blender Internal Props#########################
+ # former Space properties from removed Blender Internal
+ use_limited_texture_context: BoolProperty(
+ name="",
+ description="Use the limited version of texture user (for ‘old shading’ mode)",
+ default=True,
+ )
+ texture_context: EnumProperty(
+ name="Texture context",
+ description="Type of texture data to display and edit",
+ items=(
+ ("MATERIAL", "", "Show material textures", "MATERIAL", 0), # "Show material textures"
+ ("WORLD", "", "Show world textures", "WORLD", 1), # "Show world textures"
+ ("LAMP", "", "Show lamp textures", "LIGHT", 2), # "Show lamp textures"
+ (
+ "PARTICLES",
+ "",
+ "Show particles textures",
+ "PARTICLES",
+ 3,
+ ), # "Show particles textures"
+ (
+ "LINESTYLE",
+ "",
+ "Show linestyle textures",
+ "LINE_DATA",
+ 4,
+ ), # "Show linestyle textures"
+ (
+ "OTHER",
+ "",
+ "Show other data textures",
+ "TEXTURE_DATA",
+ 5,
+ ), # "Show other data textures"
+ ),
+ default="MATERIAL",
+ )
+
+ active_texture_index: IntProperty(
+ name="Index for texture_slots", default=0, update=brush_texture_update
+ )
+
+ transparency_method: EnumProperty(
+ name="Specular Shader Model",
+ description="Method to use for rendering transparency",
+ items=(
+ ("MASK", "Mask", "Mask the background"),
+ ("Z_TRANSPARENCY", "Z Transparency", "Use alpha buffer for transparent faces"),
+ ("RAYTRACE", "Raytrace", "Use raytracing for transparent refraction rendering"),
+ ),
+ default="MASK",
+ )
+
+ use_transparency: BoolProperty(
+ name="Transparency", description="Render material as transparent", default=False
+ )
+
+ alpha: FloatProperty(
+ name="Alpha",
+ description="Alpha transparency of the material",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+ specular_alpha: FloatProperty(
+ name="Specular alpha",
+ description="Alpha transparency for specular areas",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+ ambient: FloatProperty(
+ name="Ambient",
+ description="Amount of global ambient color the material receives",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+ diffuse_color: FloatVectorProperty(
+ name="Diffuse color",
+ description=("Diffuse color of the material"),
+ precision=4,
+ step=0.01,
+ min=0, # max=inf, soft_max=1,
+ default=(0.6, 0.6, 0.6),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ darkness: FloatProperty(
+ name="Darkness",
+ description="Minnaert darkness",
+ min=0.0,
+ max=2.0,
+ soft_min=0.0,
+ soft_max=2.0,
+ default=1.0,
+ precision=3,
+ )
+
+ diffuse_fresnel: FloatProperty(
+ name="Diffuse fresnel",
+ description="Power of Fresnel",
+ min=0.0,
+ max=5.0,
+ soft_min=0.0,
+ soft_max=5.0,
+ default=1.0,
+ precision=3,
+ )
+
+ diffuse_fresnel_factor: FloatProperty(
+ name="Diffuse fresnel factor",
+ description="Blending factor of Fresnel",
+ min=0.0,
+ max=5.0,
+ soft_min=0.0,
+ soft_max=5.0,
+ default=0.5,
+ precision=3,
+ )
+
+ diffuse_intensity: FloatProperty(
+ name="Diffuse intensity",
+ description="Amount of diffuse reflection multiplying color",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=0.8,
+ precision=3,
+ )
+
+ diffuse_ramp_blend: EnumProperty(
+ name="Diffuse ramp blend",
+ description="Blending method of the ramp and the diffuse color",
+ items=(
+ ("MIX", "Mix", ""),
+ ("ADD", "Add", ""),
+ ("MULTIPLY", "Multiply", ""),
+ ("SUBTRACT", "Subtract", ""),
+ ("SCREEN", "Screen", ""),
+ ("DIVIDE", "Divide", ""),
+ ("DIFFERENCE", "Difference", ""),
+ ("DARKEN", "Darken", ""),
+ ("LIGHTEN", "Lighten", ""),
+ ("OVERLAY", "Overlay", ""),
+ ("DODGE", "Dodge", ""),
+ ("BURN", "Burn", ""),
+ ("HUE", "Hue", ""),
+ ("SATURATION", "Saturation", ""),
+ ("VALUE", "Value", ""),
+ ("COLOR", "Color", ""),
+ ("SOFT_LIGHT", "Soft light", ""),
+ ("LINEAR_LIGHT", "Linear light", ""),
+ ),
+ default="MIX",
+ )
+
+ diffuse_ramp_factor: FloatProperty(
+ name="Factor",
+ description="Blending factor (also uses alpha in Colorband)",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+ diffuse_ramp_input: EnumProperty(
+ name="Input",
+ description="How the ramp maps on the surface",
+ items=(
+ ("SHADER", "Shader", ""),
+ ("ENERGY", "Energy", ""),
+ ("NORMAL", "Normal", ""),
+ ("RESULT", "Result", ""),
+ ),
+ default="SHADER",
+ )
+
+ diffuse_shader: EnumProperty(
+ name="Diffuse Shader Model",
+ description="How the ramp maps on the surface",
+ items=(
+ ("LAMBERT", "Lambert", "Use a Lambertian shader"),
+ ("OREN_NAYAR", "Oren-Nayar", "Use an Oren-Nayar shader"),
+ ("MINNAERT", "Minnaert", "Use a Minnaert shader"),
+ ("FRESNEL", "Fresnel", "Use a Fresnel shader"),
+ ),
+ default="LAMBERT",
+ )
+
+ diffuse_toon_size: FloatProperty(
+ name="Size",
+ description="Size of diffuse toon area",
+ min=0.0,
+ max=3.14,
+ soft_min=0.0,
+ soft_max=3.14,
+ default=0.5,
+ precision=3,
+ )
+
+ diffuse_toon_smooth: FloatProperty(
+ name="Smooth",
+ description="Smoothness of diffuse toon area",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=0.1,
+ precision=3,
+ )
+
+ emit: FloatProperty(
+ name="Emit",
+ description="Amount of light to emit",
+ min=0.0,
+ soft_min=0.0, # max=inf, soft_max=inf,
+ default=0.0,
+ precision=3,
+ )
+
+ mirror_color: FloatVectorProperty(
+ name="Mirror color",
+ description=("Mirror color of the material"),
+ precision=4,
+ step=0.01,
+ min=0, # max=inf, soft_max=1,
+ default=(0.6, 0.6, 0.6),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ roughness: FloatProperty(
+ name="Roughness",
+ description="Oren-Nayar Roughness",
+ min=0.0,
+ max=3.14,
+ soft_min=0.0,
+ soft_max=3.14,
+ precision=3,
+ default=0.5,
+ )
+
+ halo: BoolProperty(name="Halo", description=" Halo settings for the material", default=False)
+ # (was readonly in Blender2.79, never None)
+
+ line_color: FloatVectorProperty(
+ name="Line color",
+ description=("Line color used for Freestyle line rendering"),
+ precision=4,
+ step=0.01,
+ min=0, # max=inf, soft_max=1,
+ default=(0.0, 0.0, 0.0),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ # diffuse_ramp:
+ ## Color ramp used to affect diffuse shading
+ ## Type: ColorRamp, (readonly)
+
+ # cr_node = bpy.data.materials['Material'].node_tree.nodes['ColorRamp']
+ # layout.template_color_ramp(cr_node, "color_ramp", expand=True)
+
+ # ou
+
+ # class bpy.types.ColorRamp(bpy_struct)
+
+ line_priority: IntProperty(
+ name="Recursion Limit",
+ description="The line color of a higher priority is used at material boundaries",
+ min=0,
+ max=32767,
+ default=0,
+ )
+
+ specular_color: FloatVectorProperty(
+ name="Specular color",
+ description=("Specular color of the material "),
+ precision=4,
+ step=0.01,
+ min=0, # max=inf, soft_max=1,
+ default=(1.0, 1.0, 1.0),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ specular_hardness: IntProperty(
+ name="Hardness",
+ description="How hard (sharp) the specular reflection is",
+ min=1,
+ max=511,
+ default=30,
+ )
+
+ specular_intensity: FloatProperty(
+ name="Intensity",
+ description="How intense (bright) the specular reflection is",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=0.1,
+ precision=3,
+ )
+
+ specular_ior: FloatProperty(
+ name="IOR",
+ description="Specular index of refraction",
+ min=-10.0,
+ max=10.0,
+ soft_min=0.0,
+ soft_max=10.0,
+ default=1.0,
+ precision=3,
+ )
+
+ ior: FloatProperty(
+ name="IOR",
+ description="Index of refraction",
+ min=-10.0,
+ max=10.0,
+ soft_min=0.0,
+ soft_max=10.0,
+ default=1.0,
+ precision=3,
+ )
+
+ specular_shader: EnumProperty(
+ name="Specular Shader Model",
+ description="How the ramp maps on the surface",
+ items=(
+ ("COOKTORR", "CookTorr", "Use a Cook-Torrance shader"),
+ ("PHONG", "Phong", "Use a Phong shader"),
+ ("BLINN", "Blinn", "Use a Blinn shader"),
+ ("TOON", "Toon", "Use a Toon shader"),
+ ("WARDISO", "WardIso", "Use a Ward anisotropic shader"),
+ ),
+ default="COOKTORR",
+ )
+
+ specular_slope: FloatProperty(
+ name="Slope",
+ description="The standard deviation of surface slope",
+ min=0.0,
+ max=0.4,
+ soft_min=0.0,
+ soft_max=0.4,
+ default=0.1,
+ precision=3,
+ )
+
+ specular_toon_size: FloatProperty(
+ name="Size",
+ description="Size of specular toon area",
+ min=0.0,
+ max=0.53,
+ soft_min=0.0,
+ soft_max=0.53,
+ default=0.5,
+ precision=3,
+ )
+
+ specular_toon_smooth: FloatProperty(
+ name="Smooth",
+ description="Smoothness of specular toon area",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=0.1,
+ precision=3,
+ )
+
+ translucency: FloatProperty(
+ name="Translucency",
+ description="Amount of diffuse shading on the back side",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=0.0,
+ precision=3,
+ )
+
+ transparency_method: EnumProperty(
+ name="Specular Shader Model",
+ description="Method to use for rendering transparency",
+ items=(
+ ("MASK", "Mask", "Mask the background"),
+ ("Z_TRANSPARENCY", "Z Transparency", "Use an ior of 1 for transparent faces"),
+ ("RAYTRACE", "Raytrace", "Use raytracing for transparent refraction rendering"),
+ ),
+ default="MASK",
+ )
+
+ type: EnumProperty(
+ name="Type",
+ description="Material type defining how the object is rendered",
+ items=(
+ ("SURFACE", "Surface", "Render object as a surface"),
+ # TO UPDATE > USE wire MACRO AND CHANGE DESCRIPTION
+ ("WIRE", "Wire", "Render the edges of faces as wires (not supported in raytracing)"),
+ ("VOLUME", "Volume", "Render object as a volume"),
+ # TO UPDATE > USE halo MACRO AND CHANGE DESCRIPTION
+ ("HALO", "Halo", "Render object as halo particles"),
+ ),
+ default="SURFACE",
+ )
+
+ use_cast_shadows: BoolProperty(
+ name="Cast", description="Allow this material to cast shadows", default=True
+ )
+
+ use_cast_shadows_only: BoolProperty(
+ name="Cast Only",
+ description="Make objects with this material "
+ "appear invisible (not rendered), only "
+ "casting shadows",
+ default=False,
+ )
+
+ use_cubic: BoolProperty(
+ name="Cubic Interpolation",
+ description="Use cubic interpolation for diffuse " "values, for smoother transitions",
+ default=False,
+ )
+
+ use_diffuse_ramp: BoolProperty(
+ name="Ramp", description="Toggle diffuse ramp operations", default=False
+ )
+
+ use_light_group_exclusive: BoolProperty(
+ name="Exclusive",
+ description="Material uses the light group exclusively"
+ "- these lamps are excluded from other "
+ "scene lighting",
+ default=False,
+ )
+
+ use_light_group_local: BoolProperty(
+ name="Local",
+ description="When linked in, material uses local light" " group with the same name",
+ default=False,
+ )
+
+ use_mist: BoolProperty(
+ name="Use Mist",
+ description="Use mist with this material " "(in world settings)",
+ default=True,
+ )
+
+ use_nodes: BoolProperty(
+ name="Nodes",
+ # Add Icon in UI or here? icon='NODES'
+ description="Use shader nodes to render the material",
+ default=False,
+ )
+
+ use_object_color: BoolProperty(
+ name="Object Color",
+ description="Modulate the result with a per-object color",
+ default=False,
+ )
+
+ use_only_shadow: BoolProperty(
+ name="Shadows Only",
+ description="Render shadows as the material’s alpha "
+ "value, making the material transparent "
+ "except for shadowed areas",
+ default=False,
+ )
+
+ use_shadeless: BoolProperty(
+ name="Shadeless",
+ description="Make this material insensitive to " "light or shadow",
+ default=False,
+ )
+
+ use_shadows: BoolProperty(
+ name="Receive", description="Allow this material to receive shadows", default=True
+ )
+
+ use_sky: BoolProperty(
+ name="Sky",
+ description="Render this material with zero alpha, "
+ "with sky background in place (scanline only)",
+ default=False,
+ )
+
+ use_specular_ramp: BoolProperty(
+ name="Ramp", description="Toggle specular ramp operations", default=False
+ )
+
+ use_tangent_shading: BoolProperty(
+ name="Tangent Shading",
+ description="Use the material’s tangent vector instead"
+ "of the normal for shading - for "
+ "anisotropic shading effects",
+ default=False,
+ )
+
+ use_transparent_shadows: BoolProperty(
+ name="Receive Transparent",
+ description="Allow this object to receive transparent " "shadows cast through other object",
+ default=False,
+ ) # linked to fake caustics
+
+ use_vertex_color_light: BoolProperty(
+ name="Vertex Color Light",
+ description="Add vertex colors as additional lighting",
+ default=False,
+ )
+
+ use_vertex_color_paint: BoolProperty(
+ name="Vertex Color Paint",
+ description="Replace object base color with vertex "
+ "colors (multiply with ‘texture face’ "
+ "face assigned textures)",
+ default=False,
+ )
+
+ specular_ramp_blend: EnumProperty(
+ name="Specular ramp blend",
+ description="Blending method of the ramp and the specular color",
+ items=(
+ ("MIX", "Mix", ""),
+ ("ADD", "Add", ""),
+ ("MULTIPLY", "Multiply", ""),
+ ("SUBTRACT", "Subtract", ""),
+ ("SCREEN", "Screen", ""),
+ ("DIVIDE", "Divide", ""),
+ ("DIFFERENCE", "Difference", ""),
+ ("DARKEN", "Darken", ""),
+ ("LIGHTEN", "Lighten", ""),
+ ("OVERLAY", "Overlay", ""),
+ ("DODGE", "Dodge", ""),
+ ("BURN", "Burn", ""),
+ ("HUE", "Hue", ""),
+ ("SATURATION", "Saturation", ""),
+ ("VALUE", "Value", ""),
+ ("COLOR", "Color", ""),
+ ("SOFT_LIGHT", "Soft light", ""),
+ ("LINEAR_LIGHT", "Linear light", ""),
+ ),
+ default="MIX",
+ )
+
+ specular_ramp_factor: FloatProperty(
+ name="Factor",
+ description="Blending factor (also uses alpha in Colorband)",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+ specular_ramp_input: EnumProperty(
+ name="Input",
+ description="How the ramp maps on the surface",
+ items=(
+ ("SHADER", "Shader", ""),
+ ("ENERGY", "Energy", ""),
+ ("NORMAL", "Normal", ""),
+ ("RESULT", "Result", ""),
+ ),
+ default="SHADER",
+ )
+
+ irid_enable: BoolProperty(
+ name="Iridescence coating",
+ description="Newton's thin film interference (like an oil slick on a puddle of "
+ "water or the rainbow hues of a soap bubble.)",
+ default=False,
+ )
+
+ mirror_use_IOR: BoolProperty(
+ name="Correct Reflection",
+ description="Use same IOR as raytrace transparency to calculate mirror reflections. "
+ "More physically correct",
+ default=False,
+ )
+
+ mirror_metallic: BoolProperty(
+ name="Metallic Reflection",
+ description="mirror reflections get colored as diffuse (for metallic materials)",
+ default=False,
+ )
+
+ conserve_energy: BoolProperty(
+ name="Conserve Energy",
+ description="Light transmitted is more correctly reduced by mirror reflections, "
+ "also the sum of diffuse and translucency gets reduced below one ",
+ default=True,
+ )
+
+ irid_amount: FloatProperty(
+ name="amount",
+ description="Contribution of the iridescence effect to the overall surface color. "
+ "As a rule of thumb keep to around 0.25 (25% contribution) or less, "
+ "but experiment. If the surface is coming out too white, try lowering "
+ "the diffuse and possibly the ambient values of the surface",
+ min=0.0,
+ max=1.0,
+ soft_min=0.01,
+ soft_max=1.0,
+ default=0.25,
+ )
+
+ irid_thickness: FloatProperty(
+ name="thickness",
+ description="A very thin film will have a high frequency of color changes while a "
+ "thick film will have large areas of color",
+ min=0.0,
+ max=1000.0,
+ soft_min=0.1,
+ soft_max=10.0,
+ default=1,
+ )
+
+ irid_turbulence: FloatProperty(
+ name="turbulence",
+ description="This parameter varies the thickness",
+ min=0.0,
+ max=10.0,
+ soft_min=0.000,
+ soft_max=1.0,
+ default=0,
+ )
+
+ interior_fade_color: FloatVectorProperty(
+ name="Interior Fade Color",
+ description="Color of filtered attenuation for transparent " "materials",
+ precision=4,
+ step=0.01,
+ min=0.0,
+ soft_max=1.0,
+ default=(0, 0, 0),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ caustics_enable: BoolProperty(
+ name="Caustics",
+ description="use only fake refractive caustics (default) or photon based "
+ "reflective/refractive caustics",
+ default=True,
+ )
+
+ fake_caustics: BoolProperty(
+ name="Fake Caustics", description="use only (Fast) fake refractive caustics", default=True
+ )
+
+ fake_caustics_power: FloatProperty(
+ name="Fake caustics power",
+ description="Values typically range from 0.0 to 1.0 or higher. Zero is no caustics. "
+ "Low, non-zero values give broad hot-spots while higher values give "
+ "tighter, smaller simulated focal points",
+ min=0.00,
+ max=10.0,
+ soft_min=0.00,
+ soft_max=5.0,
+ default=0.15,
+ )
+
+ refraction_caustics: BoolProperty(
+ name="Refractive Caustics",
+ description="hotspots of light focused when going through the material",
+ default=True,
+ )
+
+ photons_dispersion: FloatProperty(
+ name="Chromatic Dispersion",
+ description="Light passing through will be separated according to wavelength. "
+ "This ratio of refractive indices for violet to red controls how much "
+ "the colors are spread out 1 = no dispersion, good values are 1.01 to 1.1",
+ min=1.0000,
+ max=10.000,
+ soft_min=1.0000,
+ soft_max=1.1000,
+ precision=4,
+ default=1.0000,
+ )
+
+ photons_dispersion_samples: IntProperty(
+ name="Dispersion Samples",
+ description="Number of color-steps for dispersion",
+ min=2,
+ max=128,
+ default=7,
+ )
+
+ photons_reflection: BoolProperty(
+ name="Reflective Photon Caustics",
+ description="Use this to make your Sauron's ring ;-P",
+ default=False,
+ )
+
+ refraction_type: EnumProperty(
+ items=[
+ ("1", "Z Transparency Fake Caustics", "use fake caustics"),
+ ("2", "Raytrace Photons Caustics", "use photons for refractive caustics"),
+ ],
+ name="Refraction Type:",
+ description="use fake caustics (fast) or true photons for refractive Caustics",
+ default="1",
+ )
+
+ ##################################CustomPOV Code############################
+ replacement_text: StringProperty(
+ name="Declared name:",
+ description="Type the variable name as declared either directly inlined "
+ "in your custom POV code from the text editor datablock (checked as a "
+ "source to render in it's side property panel), or this declaration can be "
+ "from an external .inc it points at. Here, name = texture {} expected",
+ default="",
+ )
+
+ # NODES
+
+ def use_material_nodes_callback(self, context):
+ """Identify if node has been added and if it is used yet or default"""
+
+ if hasattr(context.space_data, "tree_type"):
+ context.space_data.tree_type = "ObjectNodeTree"
+ mat = context.object.active_material
+ if mat.pov.material_use_nodes:
+ mat.use_nodes = True
+ tree = mat.node_tree
+ # tree.name = mat.name # XXX READONLY
+ links = tree.links
+ default = True
+ if len(tree.nodes) == 2:
+ o = 0
+ m = 0
+ for node in tree.nodes:
+ if node.type in {"OUTPUT", "MATERIAL"}:
+ tree.nodes.remove(node)
+ default = True
+ for node in tree.nodes:
+ if node.bl_idname == "PovrayOutputNode":
+ o += 1
+ if node.bl_idname == "PovrayTextureNode":
+ m += 1
+ if o == 1 and m == 1:
+ default = False
+ elif len(tree.nodes) == 0:
+ default = True
+ else:
+ default = False
+ if default:
+ output = tree.nodes.new("PovrayOutputNode")
+ output.location = 200, 200
+ tmap = tree.nodes.new("PovrayTextureNode")
+ tmap.location = 0, 200
+ links.new(tmap.outputs[0], output.inputs[0])
+ tmap.select = True
+ tree.nodes.active = tmap
+ else:
+ mat.use_nodes = False
+
+ def use_texture_nodes_callback(self, context):
+ """Identify texture nodes by filtering out output and composite ones"""
+
+ tex = context.object.active_material.active_texture
+ if tex.pov.texture_use_nodes:
+ tex.use_nodes = True
+ if len(tex.node_tree.nodes) == 2:
+ for node in tex.node_tree.nodes:
+ if node.type in {"OUTPUT", "CHECKER"}:
+ tex.node_tree.nodes.remove(node)
+ else:
+ tex.use_nodes = False
+
+ def node_active_callback(self, context):
+ """Synchronize active node with material before getting it"""
+
+ items = [] # XXX comment out > remove?
+ mat = context.material
+ mat.node_tree.nodes # XXX comment out > remove?
+ for node in mat.node_tree.nodes:
+ node.select = False
+ for node in mat.node_tree.nodes:
+ if node.name == mat.pov.material_active_node:
+ node.select = True
+ mat.node_tree.nodes.active = node
+
+ return node
+
+ def node_enum_callback(self, context):
+ items = []
+ mat = context.material
+ nodes = mat.node_tree.nodes
+ for node in nodes:
+ items.append(("%s" % node.name, "%s" % node.name, ""))
+ return items
+
+ def pigment_normal_callback(self, context):
+ render = context.scene.pov.render # XXX comment out > remove?
+ items = [("pigment", "Pigment", ""), ("normal", "Normal", "")]
+ # XXX Find any other such traces of hgpovray experiment > remove or deploy ?
+ if render == "hgpovray":
+ items = [
+ ("pigment", "Pigment", ""),
+ ("normal", "Normal", ""),
+ ("modulation", "Modulation", ""),
+ ]
+ return items
+
+ def glow_callback(self, context):
+ scene = context.scene
+ ob = context.object
+ ob.pov.mesh_write_as_old = ob.pov.mesh_write_as
+ if scene.pov.render == "uberpov" and ob.pov.glow:
+ ob.pov.mesh_write_as = "NONE"
+ else:
+ ob.pov.mesh_write_as = ob.pov.mesh_write_as_old
+
+ material_use_nodes: BoolProperty(
+ name="Use nodes", description="", update=use_material_nodes_callback, default=False
+ )
+
+ material_active_node: EnumProperty(
+ name="Active node", description="", items=node_enum_callback, update=node_active_callback
+ )
+
+ preview_settings: BoolProperty(name="Preview Settings", description="", default=False)
+
+ object_preview_transform: BoolProperty(name="Transform object", description="", default=False)
+
+ object_preview_scale: FloatProperty(name="XYZ", min=0.5, max=2.0, default=1.0)
+
+ object_preview_rotate: FloatVectorProperty(
+ name="Rotate", description="", min=-180.0, max=180.0, default=(0.0, 0.0, 0.0), subtype="XYZ"
+ )
+
+ object_preview_bgcontrast: FloatProperty(name="Contrast", min=0.0, max=1.0, default=0.5)
+
+
+class MaterialRaytraceTransparency(PropertyGroup):
+ """Declare transparency panel properties controllable in UI and translated to POV."""
+
+ depth: IntProperty(
+ name="Depth",
+ description="Maximum allowed number of light inter-refractions",
+ min=0,
+ max=32767,
+ default=2,
+ )
+
+ depth_max: FloatProperty(
+ name="Depth",
+ description="Maximum depth for light to travel through the "
+ "transparent material before becoming fully filtered (0.0 is disabled)",
+ min=0,
+ max=100,
+ default=0.0,
+ )
+
+ falloff: FloatProperty(
+ name="Falloff",
+ description="Falloff power for transmissivity filter effect (1.0 is linear)",
+ min=0.1,
+ max=10.0,
+ default=1.0,
+ precision=3,
+ )
+
+ filter: FloatProperty(
+ name="Filter",
+ description="Amount to blend in the material’s diffuse color in raytraced "
+ "transparency (simulating absorption)",
+ min=0.0,
+ max=1.0,
+ default=0.0,
+ precision=3,
+ )
+
+ fresnel: FloatProperty(
+ name="Fresnel",
+ description="Power of Fresnel for transparency (Ray or ZTransp)",
+ min=0.0,
+ max=5.0,
+ soft_min=0.0,
+ soft_max=5.0,
+ default=0.0,
+ precision=3,
+ )
+
+ fresnel_factor: FloatProperty(
+ name="Blend",
+ description="Blending factor for Fresnel",
+ min=0.0,
+ max=5.0,
+ soft_min=0.0,
+ soft_max=5.0,
+ default=1.250,
+ precision=3,
+ )
+
+ gloss_factor: FloatProperty(
+ name="Amount",
+ description="The clarity of the refraction. "
+ "(values < 1.0 give diffuse, blurry refractions)",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+ gloss_samples: IntProperty(
+ name="Samples",
+ description="frequency of the noise sample used for blurry refractions",
+ min=0,
+ max=1024,
+ default=18,
+ )
+
+ gloss_threshold: FloatProperty(
+ name="Threshold",
+ description="Threshold for adaptive sampling (if a sample "
+ "contributes less than this amount [as a percentage], "
+ "sampling is stopped)",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=0.005,
+ precision=3,
+ )
+
+ ior: FloatProperty(
+ name="IOR",
+ description="Sets angular index of refraction for raytraced refraction",
+ min=-0.0,
+ max=10.0,
+ soft_min=0.25,
+ soft_max=4.0,
+ default=1.3,
+ )
+
+
+class MaterialRaytraceMirror(PropertyGroup):
+ """Declare reflection panel properties controllable in UI and translated to POV."""
+
+ bl_description = ("Raytraced reflection settings for the Material",)
+
+ use: BoolProperty(name="Mirror", description="Enable raytraced reflections", default=False)
+
+ depth: IntProperty(
+ name="Depth",
+ description="Maximum allowed number of light inter-reflections",
+ min=0,
+ max=32767,
+ default=2,
+ )
+
+ distance: FloatProperty(
+ name="Max Dist",
+ description="Maximum distance of reflected rays "
+ "(reflections further than this range "
+ "fade to sky color or material color)",
+ min=0.0,
+ max=100000.0,
+ soft_min=0.0,
+ soft_max=10000.0,
+ default=0.0,
+ precision=3,
+ )
+
+ fade_to: EnumProperty(
+ items=[
+ ("FADE_TO_SKY", "Fade to sky", ""),
+ ("FADE_TO_MATERIAL", "Fade to material color", ""),
+ ],
+ name="Fade-out Color",
+ description="The color that rays with no intersection within the "
+ "Max Distance take (material color can be best for "
+ "indoor scenes, sky color for outdoor)",
+ default="FADE_TO_SKY",
+ )
+
+ fresnel: FloatProperty(
+ name="Fresnel",
+ description="Power of Fresnel for mirror reflection",
+ min=0.0,
+ max=5.0,
+ soft_min=0.0,
+ soft_max=5.0,
+ default=0.0,
+ precision=3,
+ )
+
+ fresnel_factor: FloatProperty(
+ name="Blend",
+ description="Blending factor for Fresnel",
+ min=0.0,
+ max=5.0,
+ soft_min=0.0,
+ soft_max=5.0,
+ default=1.250,
+ precision=3,
+ )
+
+ gloss_anisotropic: FloatProperty(
+ name="Anisotropic",
+ description="The shape of the reflection, from 0.0 (circular) "
+ "to 1.0 (fully stretched along the tangent",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+ gloss_factor: FloatProperty(
+ name="Amount",
+ description="The shininess of the reflection "
+ "(values < 1.0 give diffuse, blurry reflections)",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+ gloss_samples: IntProperty(
+ name="Noise",
+ description="Frequency of the noise pattern bumps averaged for blurry reflections",
+ min=0,
+ max=1024,
+ default=18,
+ )
+
+ gloss_threshold: FloatProperty(
+ name="Threshold",
+ description="Threshold for adaptive sampling (if a sample "
+ "contributes less than this amount [as a percentage], "
+ "sampling is stopped)",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=0.005,
+ precision=3,
+ )
+
+ mirror_color: FloatVectorProperty(
+ name="Mirror color",
+ description=("Mirror color of the material"),
+ precision=4,
+ step=0.01,
+ default=(1.0, 1.0, 1.0),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ reflect_factor: FloatProperty(
+ name="Reflectivity",
+ description="Amount of mirror reflection for raytrace",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+
+class MaterialSubsurfaceScattering(PropertyGroup):
+ r"""Declare SSS/SSTL properties controllable in UI and translated to POV."""
+
+ bl_description = ("Subsurface scattering settings for the material",)
+
+ use: BoolProperty(
+ name="Subsurface Scattering",
+ description="Enable diffuse subsurface scatting " "effects in a material",
+ default=False,
+ )
+
+ back: FloatProperty(
+ name="Back",
+ description="Back scattering weight",
+ min=0.0,
+ max=10.0,
+ soft_min=0.0,
+ soft_max=10.0,
+ default=1.0,
+ precision=3,
+ )
+
+ color: FloatVectorProperty(
+ name="Scattering color",
+ description=("Scattering color"),
+ precision=4,
+ step=0.01,
+ default=(0.604, 0.604, 0.604),
+ options={"ANIMATABLE"},
+ subtype="COLOR",
+ )
+
+ color_factor: FloatProperty(
+ name="Color",
+ description="Blend factor for SSS colors",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ precision=3,
+ )
+
+ error_threshold: FloatProperty(
+ name="Error",
+ description="Error tolerance (low values are slower and higher quality)",
+ default=0.050,
+ precision=3,
+ )
+
+ front: FloatProperty(
+ name="Front",
+ description="Front scattering weight",
+ min=0.0,
+ max=2.0,
+ soft_min=0.0,
+ soft_max=2.0,
+ default=1.0,
+ precision=3,
+ )
+
+ ior: FloatProperty(
+ name="IOR",
+ description="Index of refraction (higher values are denser)",
+ min=-0.0,
+ max=10.0,
+ soft_min=0.1,
+ soft_max=2.0,
+ default=1.3,
+ )
+
+ radius: FloatVectorProperty(
+ name="RGB Radius",
+ description=("Mean red/green/blue scattering path length"),
+ precision=4,
+ step=0.01,
+ min=0.001,
+ default=(1.0, 1.0, 1.0),
+ options={"ANIMATABLE"},
+ )
+
+ scale: FloatProperty(
+ name="Scale", description="Object scale factor", default=0.100, precision=3
+ )
+
+ texture_factor: FloatProperty(
+ name="Texture",
+ description="Texture scattering blend factor",
+ min=0.0,
+ max=1.0,
+ soft_min=0.0,
+ soft_max=1.0,
+ default=0.0,
+ precision=3,
+ )
+
+
+class MaterialStrandSettings(PropertyGroup):
+ """Declare strand properties controllable in UI and translated to POV."""
+
+ bl_description = ("Strand settings for the material",)
+
+ blend_distance: FloatProperty(
+ name="Distance",
+ description="Worldspace distance over which to blend in the surface normal",
+ min=0.0,
+ max=10.0,
+ soft_min=0.0,
+ soft_max=10.0,
+ default=0.0,
+ precision=3,
+ )
+
+ root_size: FloatProperty(
+ name="Root",
+ description="Start size of strands in pixels or Blender units",
+ min=0.25,
+ default=1.0,
+ precision=5,
+ )
+
+ shape: FloatProperty(
+ name="Shape",
+ description="Positive values make strands rounder, negative ones make strands spiky",
+ min=-0.9,
+ max=0.9,
+ default=0.0,
+ precision=3,
+ )
+
+ size_min: FloatProperty(
+ name="Minimum",
+ description="Minimum size of strands in pixels",
+ min=0.001,
+ max=10.0,
+ default=1.0,
+ precision=3,
+ )
+
+ tip_size: FloatProperty(
+ name="Tip",
+ description="End size of strands in pixels or Blender units",
+ min=0.0,
+ default=1.0,
+ precision=5,
+ )
+
+ use_blender_units: BoolProperty(
+ name="Blender Units",
+ description="Use Blender units for widths instead of pixels",
+ default=False,
+ )
+
+ use_surface_diffuse: BoolProperty(
+ name="Surface diffuse",
+ description="Make diffuse shading more similar to shading the surface",
+ default=False,
+ )
+
+ use_tangent_shading: BoolProperty(
+ name="Tangent Shading",
+ description="Use direction of strands as normal for tangent-shading",
+ default=True,
+ )
+
+ uv_layer: StringProperty(
+ name="UV Layer",
+ # icon="GROUP_UVS",
+ description="Name of UV map to override",
+ default="",
+ )
+
+ width_fade: FloatProperty(
+ name="Width Fade",
+ description="Transparency along the width of the strand",
+ min=0.0,
+ max=2.0,
+ default=0.0,
+ precision=3,
+ )
+
+ # halo
+
+ # Halo settings for the material
+ # Type: MaterialHalo, (readonly, never None)
+
+ # ambient
+
+ # Amount of global ambient color the material receives
+ # Type: float in [0, 1], default 0.0
+
+ # darkness
+
+ # Minnaert darkness
+ # Type: float in [0, 2], default 0.0
+
+ # diffuse_color
+
+ # Diffuse color of the material
+ # Type: float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
+
+ # diffuse_fresnel
+
+ # Power of Fresnel
+ # Type: float in [0, 5], default 0.0
+
+ # diffuse_fresnel_factor
+
+ # Blending factor of Fresnel
+ # Type: float in [0, 5], default 0.0
+
+ # diffuse_intensity
+
+ # Amount of diffuse reflection
+ # Type: float in [0, 1], default 0.0
+
+ # diffuse_ramp
+
+ # Color ramp used to affect diffuse shading
+ # Type: ColorRamp, (readonly)
+
+ # diffuse_ramp_blend
+
+ # Blending method of the ramp and the diffuse color
+ # Type: enum in [‘MIX’, ‘ADD’, ‘MULTIPLY’, ‘SUBTRACT’, ‘SCREEN’, ‘DIVIDE’, ‘DIFFERENCE’, ‘DARKEN’, ‘LIGHTEN’, ‘OVERLAY’, ‘DODGE’, ‘BURN’, ‘HUE’, ‘SATURATION’, ‘VALUE’, ‘COLOR’, ‘SOFT_LIGHT’, ‘LINEAR_LIGHT’], default ‘MIX’
+
+ # diffuse_ramp_factor
+
+ # Blending factor (also uses alpha in Colorband)
+ # Type: float in [0, 1], default 0.0
+
+ # diffuse_ramp_input
+
+ # How the ramp maps on the surface
+ # Type: enum in [‘SHADER’, ‘ENERGY’, ‘NORMAL’, ‘RESULT’], default ‘SHADER’
+
+ # diffuse_shader
+
+ # LAMBERT Lambert, Use a Lambertian shader.
+ # OREN_NAYAR Oren-Nayar, Use an Oren-Nayar shader.
+ # TOON Toon, Use a toon shader.
+ # MINNAERT Minnaert, Use a Minnaert shader.
+ # FRESNEL Fresnel, Use a Fresnel shader.
+
+ # Type: enum in [‘LAMBERT’, ‘OREN_NAYAR’, ‘TOON’, ‘MINNAERT’, ‘FRESNEL’], default ‘LAMBERT’
+
+ # diffuse_toon_size
+
+ # Size of diffuse toon area
+ # Type: float in [0, 3.14], default 0.0
+
+ # diffuse_toon_smooth
+
+ # Smoothness of diffuse toon area
+ # Type: float in [0, 1], default 0.0
+
+ # emit
+
+ # Amount of light to emit
+ # Type: float in [0, inf], default 0.0
+
+ # game_settings
+
+ # Game material settings
+ # Type: MaterialGameSettings, (readonly, never None)
+
+ # halo
+
+ # Halo settings for the material
+ # Type: MaterialHalo, (readonly, never None)
+
+ # invert_z
+
+ # Render material’s faces with an inverted Z buffer (scanline only)
+ # Type: boolean, default False
+
+ # light_group
+
+ # Limit lighting to lamps in this Group
+ # Type: Group
+
+ # line_color
+
+ # Line color used for Freestyle line rendering
+ # Type: float array of 4 items in [0, inf], default (0.0, 0.0, 0.0, 0.0)
+
+ # line_priority
+
+ # The line color of a higher priority is used at material boundaries
+ # Type: int in [0, 32767], default 0
+
+ # mirror_color
+
+ # Mirror color of the material
+ # Type: float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
+
+ # node_tree
+
+ # Node tree for node based materials
+ # Type: NodeTree, (readonly)
+
+ # offset_z
+
+ # Give faces an artificial offset in the Z buffer for Z transparency
+ # Type: float in [-inf, inf], default 0.0
+
+ # paint_active_slot
+
+ # Index of active texture paint slot
+ # Type: int in [0, 32767], default 0
+
+ # paint_clone_slot
+
+ # Index of clone texture paint slot
+ # Type: int in [0, 32767], default 0
+
+ # pass_index
+
+ # Index number for the “Material Index” render pass
+ # Type: int in [0, 32767], default 0
+
+ # physics
+
+ # Game physics settings
+ # Type: MaterialPhysics, (readonly, never None)
+
+ # preview_render_type
+
+ # Type of preview render
+
+ # FLAT Flat, Flat XY plane.
+ # SPHERE Sphere, Sphere.
+ # CUBE Cube, Cube.
+ # MONKEY Monkey, Monkey.
+ # HAIR Hair, Hair strands.
+ # SPHERE_A World Sphere, Large sphere with sky.
+
+ # Type: enum in [‘FLAT’, ‘SPHERE’, ‘CUBE’, ‘MONKEY’, ‘HAIR’, ‘SPHERE_A’], default ‘FLAT’
+
+ # raytrace_mirror
+
+ # Raytraced reflection settings for the material
+ # Type: MaterialRaytraceMirror, (readonly, never None)
+
+ # raytrace_transparency
+
+ # Raytraced transparency settings for the material
+ # Type: MaterialRaytraceTransparency, (readonly, never None)
+
+ # roughness
+
+ # Oren-Nayar Roughness
+ # Type: float in [0, 3.14], default 0.0
+
+ # shadow_buffer_bias
+
+ # Factor to multiply shadow buffer bias with (0 is ignore)
+ # Type: float in [0, 10], default 0.0
+
+ # shadow_cast_alpha
+
+ # Shadow casting alpha, in use for Irregular and Deep shadow buffer
+ # Type: float in [0.001, 1], default 0.0
+
+ # shadow_only_type
+
+ # How to draw shadows
+
+ # SHADOW_ONLY_OLD Shadow and Distance, Old shadow only method.
+ # SHADOW_ONLY Shadow Only, Improved shadow only method.
+ # SHADOW_ONLY_SHADED Shadow and Shading, Improved shadow only method which also renders lightless areas as shadows.
+
+ # Type: enum in [‘SHADOW_ONLY_OLD’, ‘SHADOW_ONLY’, ‘SHADOW_ONLY_SHADED’], default ‘SHADOW_ONLY_OLD’
+
+ # shadow_ray_bias
+
+ # Shadow raytracing bias to prevent terminator problems on shadow boundary
+ # Type: float in [0, 0.25], default 0.0
+
+ # specular_color
+
+ # Specular color of the material
+ # Type: float array of 3 items in [0, inf], default (0.0, 0.0, 0.0)
+
+ # specular_hardness
+
+ # How hard (sharp) the specular reflection is
+ # Type: int in [1, 511], default 0
+
+ # specular_intensity
+
+ # How intense (bright) the specular reflection is
+ # Type: float in [0, 1], default 0.0
+
+ # specular_ior
+
+ # Specular index of refraction
+ # Type: float in [1, 10], default 0.0
+
+ # specular_ramp
+
+ # Color ramp used to affect specular shading
+ # Type: ColorRamp, (readonly)
+
+ # specular_ramp_blend
+
+ # Blending method of the ramp and the specular color
+ # Type: enum in [‘MIX’, ‘ADD’, ‘MULTIPLY’, ‘SUBTRACT’, ‘SCREEN’, ‘DIVIDE’, ‘DIFFERENCE’, ‘DARKEN’, ‘LIGHTEN’, ‘OVERLAY’, ‘DODGE’, ‘BURN’, ‘HUE’, ‘SATURATION’, ‘VALUE’, ‘COLOR’, ‘SOFT_LIGHT’, ‘LINEAR_LIGHT’], default ‘MIX’
+
+ # specular_ramp_factor
+
+ # Blending factor (also uses alpha in Colorband)
+ # Type: float in [0, 1], default 0.0
+
+ # specular_ramp_input
+
+ # How the ramp maps on the surface
+ # Type: enum in [‘SHADER’, ‘ENERGY’, ‘NORMAL’, ‘RESULT’], default ‘SHADER’
+ # specular_shader
+
+ # COOKTORR CookTorr, Use a Cook-Torrance shader.
+ # PHONG Phong, Use a Phong shader.
+ # BLINN Blinn, Use a Blinn shader.
+ # TOON Toon, Use a toon shader.
+ # WARDISO WardIso, Use a Ward anisotropic shader.
+
+ # Type: enum in [‘COOKTORR’, ‘PHONG’, ‘BLINN’, ‘TOON’, ‘WARDISO’], default ‘COOKTORR’
+
+ # specular_slope
+
+ # The standard deviation of surface slope
+ # Type: float in [0, 0.4], default 0.0
+
+ # specular_toon_size
+
+ # Size of specular toon area
+ # Type: float in [0, 1.53], default 0.0
+
+ # specular_toon_smooth
+
+ # Smoothness of specular toon area
+ # Type: float in [0, 1], default 0.0
+
+ # strand
+
+ # Strand settings for the material
+ # Type: MaterialStrand, (readonly, never None)
+
+ # subsurface_scattering
+
+ # Subsurface scattering settings for the material
+ # Type: MaterialSubsurfaceScattering, (readonly, never None)
+
+ # texture_paint_images
+
+ # Texture images used for texture painting
+ # Type: bpy_prop_collection of Image, (readonly)
+
+ # texture_paint_slots
+
+ # Texture slots defining the mapping and influence of textures
+ # Type: bpy_prop_collection of TexPaintSlot, (readonly)
+
+ # texture_slots
+
+ # Texture slots defining the mapping and influence of textures
+ # Type: MaterialTextureSlots bpy_prop_collection of MaterialTextureSlot, (readonly)
+
+ # translucency
+
+ # Amount of diffuse shading on the back side
+ # Type: float in [0, 1], default 0.0
+
+ # transparency_method
+
+ # Method to use for rendering transparency
+
+ # MASK Mask, Mask the background.
+ # Z_TRANSPARENCY Z Transparency, Use alpha buffer for transparent faces.
+ # RAYTRACE Raytrace, Use raytracing for transparent refraction rendering.
+
+ # Type: enum in [‘MASK’, ‘Z_TRANSPARENCY’, ‘RAYTRACE’], default ‘MASK’
+
+ # type
+
+ # Material type defining how the object is rendered
+
+ # SURFACE Surface, Render object as a surface.
+ # WIRE Wire, Render the edges of faces as wires (not supported in raytracing).
+ # VOLUME Volume, Render object as a volume.
+ # HALO Halo, Render object as halo particles.
+
+ # Type: enum in [‘SURFACE’, ‘WIRE’, ‘VOLUME’, ‘HALO’], default ‘SURFACE’
+
+ # use_cast_approximate
+
+ # Allow this material to cast shadows when using approximate ambient occlusion
+ # Type: boolean, default False
+
+ # use_cast_buffer_shadows
+
+ # Allow this material to cast shadows from shadow buffer lamps
+ # Type: boolean, default False
+
+ # use_cast_shadows
+
+ # Allow this material to cast shadows
+ # Type: boolean, default False
+
+ # use_cast_shadows_only
+
+ # Make objects with this material appear invisible (not rendered), only casting shadows
+ # Type: boolean, default False
+
+ # use_cubic
+
+ # Use cubic interpolation for diffuse values, for smoother transitions
+ # Type: boolean, default False
+
+ # use_diffuse_ramp
+
+ # Toggle diffuse ramp operations
+ # Type: boolean, default False
+
+ # use_face_texture
+
+ # Replace the object’s base color with color from UV map image textures
+ # Type: boolean, default False
+
+ # use_face_texture_alpha
+
+ # Replace the object’s base alpha value with alpha from UV map image textures
+ # Type: boolean, default False
+
+ # use_full_oversampling
+
+ # Force this material to render full shading/textures for all anti-aliasing samples
+ # Type: boolean, default False
+
+ # use_light_group_exclusive
+
+ # Material uses the light group exclusively - these lamps are excluded from other scene lighting
+ # Type: boolean, default False
+
+ # use_light_group_local
+
+ # When linked in, material uses local light group with the same name
+ # Type: boolean, default False
+
+ # use_mist
+
+ # Use mist with this material (in world settings)
+ # Type: boolean, default False
+
+ # use_nodes
+
+ # Use shader nodes to render the material
+ # Type: boolean, default False
+
+ # use_object_color
+
+ # Modulate the result with a per-object color
+ # Type: boolean, default False
+
+ # use_only_shadow
+
+ # Render shadows as the material’s alpha value, making the material transparent except for shadowed areas
+ # Type: boolean, default False
+
+ # use_ray_shadow_bias
+
+ # Prevent raytraced shadow errors on surfaces with smooth shaded normals (terminator problem)
+ # Type: boolean, default False
+
+ # use_raytrace
+
+ # Include this material and geometry that uses it in raytracing calculations
+ # Type: boolean, default False
+
+ # use_shadeless
+
+ # Make this material insensitive to light or shadow
+ # Type: boolean, default False
+
+ # use_shadows
+
+ # Allow this material to receive shadows
+ # Type: boolean, default False
+
+ # use_sky
+
+ # Render this material with zero alpha, with sky background in place (scanline only)
+ # Type: boolean, default False
+
+ # use_specular_ramp
+
+ # Toggle specular ramp operations
+ # Type: boolean, default False
+
+ # use_tangent_shading
+
+ # Use the material’s tangent vector instead of the normal for shading - for anisotropic shading effects
+ # Type: boolean, default False
+
+ # use_textures
+
+ # Enable/Disable each texture
+ # Type: boolean array of 18 items, default (False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
+
+ # use_transparency
+
+ # Render material as transparent
+ # Type: boolean, default False
+
+ # use_transparent_shadows
+
+ # Allow this object to receive transparent shadows cast through other objects
+ # Type: boolean, default False
+
+ # use_uv_project
+
+ # Use to ensure UV interpolation is correct for camera projections (use with UV project modifier)
+ # Type: boolean, default False
+
+ # use_vertex_color_light
+
+ # Add vertex colors as additional lighting
+ # Type: boolean, default False
+
+ # use_vertex_color_paint
+
+ # Replace object base color with vertex colors (multiply with ‘texture face’ face assigned textures)
+ # Type: boolean, default False
+
+ # volume
+
+ # Volume settings for the material
+ # Type: MaterialVolume, (readonly, never None)
+ """
+ (mat.type in {'SURFACE', 'WIRE', 'VOLUME'})
+ "use_transparency")
+
+
+
+ mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY'
+
+
+
+
+ col.prop(mat, "use_raytrace")
+ col.prop(mat, "use_full_oversampling")
+
+ sub.prop(mat, "use_sky")
+
+
+ col.prop(mat, "use_cast_shadows", text="Cast")
+ col.prop(mat, "use_cast_shadows_only", text="Cast Only")
+ col.prop(mat, "use_cast_buffer_shadows")
+
+ sub.active = mat.use_cast_buffer_shadows
+ sub.prop(mat, "shadow_cast_alpha", text="Casting Alpha")
+ col.prop(mat, "use_cast_approximate")
+
+
+
+ col.prop(mat, "diffuse_color", text="")
+
+ sub.active = (not mat.use_shadeless)
+
+ sub.prop(mat, "diffuse_intensity", text="Intensity")
+
+
+ col.prop(mat, "diffuse_shader", text="")
+ col.prop(mat, "use_diffuse_ramp", text="Ramp")
+
+
+ if mat.diffuse_shader == 'OREN_NAYAR':
+ col.prop(mat, "roughness")
+ elif mat.diffuse_shader == 'MINNAERT':
+ col.prop(mat, "darkness")
+ elif mat.diffuse_shader == 'TOON':
+
+ row.prop(mat, "diffuse_toon_size", text="Size")
+ row.prop(mat, "diffuse_toon_smooth", text="Smooth")
+ elif mat.diffuse_shader == 'FRESNEL':
+
+ row.prop(mat, "diffuse_fresnel", text="Fresnel")
+ row.prop(mat, "diffuse_fresnel_factor", text="Factor")
+
+ if mat.use_diffuse_ramp:
+
+ col.template_color_ramp(mat, "diffuse_ramp", expand=True)
+
+
+
+ row.prop(mat, "diffuse_ramp_input", text="Input")
+ row.prop(mat, "diffuse_ramp_blend", text="Blend")
+
+ col.prop(mat, "diffuse_ramp_factor", text="Factor")
+
+
+
+
+ col.prop(mat, "specular_color", text="")
+ col.prop(mat, "specular_intensity", text="Intensity")
+
+ col.prop(mat, "specular_shader", text="")
+ col.prop(mat, "use_specular_ramp", text="Ramp")
+
+ if mat.specular_shader in {'COOKTORR', 'PHONG'}:
+ col.prop(mat, "specular_hardness", text="Hardness")
+ elif mat.specular_shader == 'BLINN':
+
+ row.prop(mat, "specular_hardness", text="Hardness")
+ row.prop(mat, "specular_ior", text="IOR")
+ elif mat.specular_shader == 'WARDISO':
+ col.prop(mat, "specular_slope", text="Slope")
+ elif mat.specular_shader == 'TOON':
+
+ row.prop(mat, "specular_toon_size", text="Size")
+ row.prop(mat, "specular_toon_smooth", text="Smooth")
+
+ if mat.use_specular_ramp:
+ layout.separator()
+ layout.template_color_ramp(mat, "specular_ramp", expand=True)
+ layout.separator()
+
+ row = layout.row()
+ row.prop(mat, "specular_ramp_input", text="Input")
+ row.prop(mat, "specular_ramp_blend", text="Blend")
+
+ layout.prop(mat, "specular_ramp_factor", text="Factor")
+
+
+ class MATERIAL_PT_shading(MaterialButtonsPanel, Panel):
+ bl_label = "Shading"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = active_node_mat(context.material)
+
+ if mat.type in {'SURFACE', 'WIRE'}:
+ split = layout.split()
+
+ col = split.column()
+ sub = col.column()
+ sub.active = not mat.use_shadeless
+ sub.prop(mat, "emit")
+ sub.prop(mat, "ambient")
+ sub = col.column()
+ sub.prop(mat, "translucency")
+
+ col = split.column()
+ col.prop(mat, "use_shadeless")
+ sub = col.column()
+ sub.active = not mat.use_shadeless
+ sub.prop(mat, "use_tangent_shading")
+ sub.prop(mat, "use_cubic")
+
+
+ class MATERIAL_PT_transp(MaterialButtonsPanel, Panel):
+ bl_label = "Transparency"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ mat = context.material
+
+ if simple_material(mat):
+ self.layout.prop(mat, "use_transparency", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ base_mat = context.material
+ mat = active_node_mat(context.material)
+ rayt = mat.raytrace_transparency
+
+ if simple_material(base_mat):
+ row = layout.row()
+ row.active = mat.use_transparency
+ row.prop(mat, "transparency_method", expand=True)
+
+ split = layout.split()
+ split.active = base_mat.use_transparency
+
+ col = split.column()
+ col.prop(mat, "alpha")
+ row = col.row()
+ row.active = (base_mat.transparency_method != 'MASK') and (not mat.use_shadeless)
+ row.prop(mat, "specular_alpha", text="Specular")
+
+ col = split.column()
+ col.active = (not mat.use_shadeless)
+ col.prop(rayt, "fresnel")
+ sub = col.column()
+ sub.active = (rayt.fresnel > 0.0)
+ sub.prop(rayt, "fresnel_factor", text="Blend")
+
+ if base_mat.transparency_method == 'RAYTRACE':
+ layout.separator()
+ split = layout.split()
+ split.active = base_mat.use_transparency
+
+ col = split.column()
+ col.prop(rayt, "ior")
+ col.prop(rayt, "filter")
+ col.prop(rayt, "falloff")
+ col.prop(rayt, "depth_max")
+ col.prop(rayt, "depth")
+
+ col = split.column()
+ col.label(text="Gloss:")
+ col.prop(rayt, "gloss_factor", text="Amount")
+ sub = col.column()
+ sub.active = rayt.gloss_factor < 1.0
+ sub.prop(rayt, "gloss_threshold", text="Threshold")
+ sub.prop(rayt, "gloss_samples", text="Samples")
+
+
+ class MATERIAL_PT_mirror(MaterialButtonsPanel, Panel):
+ bl_label = "Mirror"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ raym = active_node_mat(context.material).raytrace_mirror
+
+ self.layout.prop(raym, "use", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = active_node_mat(context.material)
+ raym = mat.raytrace_mirror
+
+ layout.active = raym.use
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(raym, "reflect_factor")
+ col.prop(mat, "mirror_color", text="")
+
+ col = split.column()
+ col.prop(raym, "fresnel")
+ sub = col.column()
+ sub.active = (raym.fresnel > 0.0)
+ sub.prop(raym, "fresnel_factor", text="Blend")
+
+ split = layout.split()
+
+ col = split.column()
+ col.separator()
+ col.prop(raym, "depth")
+ col.prop(raym, "distance", text="Max Dist")
+ col.separator()
+ sub = col.split(percentage=0.4)
+ sub.active = (raym.distance > 0.0)
+ sub.label(text="Fade To:")
+ sub.prop(raym, "fade_to", text="")
+
+ col = split.column()
+ col.label(text="Gloss:")
+ col.prop(raym, "gloss_factor", text="Amount")
+ sub = col.column()
+ sub.active = (raym.gloss_factor < 1.0)
+ sub.prop(raym, "gloss_threshold", text="Threshold")
+ sub.prop(raym, "gloss_samples", text="Samples")
+ sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
+
+
+ class MATERIAL_PT_sss(MaterialButtonsPanel, Panel):
+ bl_label = "Subsurface Scattering"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ mat = active_node_mat(context.material)
+ sss = mat.subsurface_scattering
+
+ self.layout.active = (not mat.use_shadeless)
+ self.layout.prop(sss, "use", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = active_node_mat(context.material)
+ sss = mat.subsurface_scattering
+
+ layout.active = (sss.use) and (not mat.use_shadeless)
+
+ row = layout.row().split()
+ sub = row.row(align=True).split(align=True, percentage=0.75)
+ sub.menu("MATERIAL_MT_sss_presets", text=bpy.types.MATERIAL_MT_sss_presets.bl_label)
+ sub.operator("material.sss_preset_add", text="", icon='ZOOMIN')
+ sub.operator("material.sss_preset_add", text="", icon='ZOOMOUT').remove_active = True
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(sss, "ior")
+ col.prop(sss, "scale")
+ col.prop(sss, "color", text="")
+ col.prop(sss, "radius", text="RGB Radius", expand=True)
+
+ col = split.column()
+ sub = col.column(align=True)
+ sub.label(text="Blend:")
+ sub.prop(sss, "color_factor", text="Color")
+ sub.prop(sss, "texture_factor", text="Texture")
+ sub.label(text="Scattering Weight:")
+ sub.prop(sss, "front")
+ sub.prop(sss, "back")
+ col.separator()
+ col.prop(sss, "error_threshold", text="Error")
+
+
+ class MATERIAL_PT_halo(MaterialButtonsPanel, Panel):
+ bl_label = "Halo"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = context.material # don't use node material
+ halo = mat.halo
+
+ def number_but(layout, toggle, number, name, color):
+ row = layout.row(align=True)
+ row.prop(halo, toggle, text="")
+ sub = row.column(align=True)
+ sub.active = getattr(halo, toggle)
+ sub.prop(halo, number, text=name, translate=False)
+ if not color == "":
+ sub.prop(mat, color, text="")
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(mat, "alpha")
+ col.prop(mat, "diffuse_color", text="")
+ col.prop(halo, "seed")
+
+ col = split.column()
+ col.prop(halo, "size")
+ col.prop(halo, "hardness")
+ col.prop(halo, "add")
+
+ layout.label(text="Options:")
+
+ split = layout.split()
+ col = split.column()
+ col.prop(halo, "use_texture")
+ col.prop(halo, "use_vertex_normal")
+ col.prop(halo, "use_extreme_alpha")
+ col.prop(halo, "use_shaded")
+ col.prop(halo, "use_soft")
+
+ col = split.column()
+ number_but(col, "use_ring", "ring_count", iface_("Rings"), "mirror_color")
+ number_but(col, "use_lines", "line_count", iface_("Lines"), "specular_color")
+ number_but(col, "use_star", "star_tip_count", iface_("Star Tips"), "")
+
+
+ class MATERIAL_PT_flare(MaterialButtonsPanel, Panel):
+ bl_label = "Flare"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ mat = context.material
+ engine = context.scene.render.engine
+ return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ halo = context.material.halo
+
+ self.layout.prop(halo, "use_flare_mode", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = context.material # don't use node material
+ halo = mat.halo
+
+ layout.active = halo.use_flare_mode
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(halo, "flare_size", text="Size")
+ col.prop(halo, "flare_boost", text="Boost")
+ col.prop(halo, "flare_seed", text="Seed")
+
+ col = split.column()
+ col.prop(halo, "flare_subflare_count", text="Subflares")
+ col.prop(halo, "flare_subflare_size", text="Subsize")
+
+ """
+
+
+#######################End Old Blender Internal Props##########################
+
+
+classes = (
+ RenderPovSettingsMaterial,
+ MaterialRaytraceTransparency,
+ MaterialRaytraceMirror,
+ MaterialSubsurfaceScattering,
+ MaterialStrandSettings,
+)
+
+
+def register():
+ for cls in classes:
+ register_class(cls)
+
+ bpy.types.Material.pov = PointerProperty(type=RenderPovSettingsMaterial)
+ bpy.types.Material.pov_raytrace_transparency = PointerProperty(
+ type=MaterialRaytraceTransparency
+ )
+ bpy.types.Material.pov_subsurface_scattering = PointerProperty(
+ type=MaterialSubsurfaceScattering
+ )
+ bpy.types.Material.strand = PointerProperty(type=MaterialStrandSettings)
+ bpy.types.Material.pov_raytrace_mirror = PointerProperty(type=MaterialRaytraceMirror)
+
+
+def unregister():
+ del bpy.types.Material.pov_subsurface_scattering
+ del bpy.types.Material.strand
+ del bpy.types.Material.pov_raytrace_mirror
+ del bpy.types.Material.pov_raytrace_transparency
+ del bpy.types.Material.pov
+
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/texturing.py b/render_povray/texturing.py
new file mode 100755
index 00000000..e070dbe9
--- /dev/null
+++ b/render_povray/texturing.py
@@ -0,0 +1,902 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# #**** END GPL LICENSE BLOCK #****
+
+# <pep8 compliant>
+
+"""Translate blender texture influences into POV."""
+import os
+import bpy
+
+
+def write_texture_influence(
+ using_uberpov,
+ mater,
+ material_names_dictionary,
+ local_material_names,
+ path_image,
+ exported_lights_count,
+ image_format,
+ img_map,
+ img_map_transforms,
+ tab_write,
+ comments,
+ string_strip_hyphen,
+ safety,
+ col,
+ preview_dir,
+ unpacked_images,
+):
+ """Translate Blender texture influences to various POV texture tricks and write to pov file."""
+ material_finish = material_names_dictionary[mater.name]
+ if mater.pov.use_transparency:
+ trans = 1.0 - mater.pov.alpha
+ else:
+ trans = 0.0
+ if (mater.pov.specular_color.s == 0.0) or (mater.pov.diffuse_shader == "MINNAERT"):
+ # No layered texture because of aoi pattern used for minnaert and pov can't layer patterned
+ colored_specular_found = False
+ else:
+ colored_specular_found = True
+
+ if mater.pov.use_transparency and mater.pov.transparency_method == "RAYTRACE":
+ pov_filter = mater.pov_raytrace_transparency.filter * (1.0 - mater.pov.alpha)
+ trans = (1.0 - mater.pov.alpha) - pov_filter
+ else:
+ pov_filter = 0.0
+
+ ##############SF
+ texture_dif = ""
+ texture_spec = ""
+ texture_norm = ""
+ texture_alpha = ""
+ # procedural_flag=False
+ tmpidx = -1
+ for t in mater.pov_texture_slots:
+
+ tmpidx += 1
+ # index = mater.pov.active_texture_index
+ slot = mater.pov_texture_slots[tmpidx] # [index]
+ povtex = slot.texture # slot.name
+ tex = bpy.data.textures[povtex]
+
+ if t and (t.use and (tex is not None)):
+ # 'NONE' ('NONE' type texture is different from no texture covered above)
+ if tex.type == "NONE" and tex.pov.tex_pattern_type == "emulator":
+ continue # move to next slot
+
+ # Implicit else-if (as not skipped by previous "continue")
+ # PROCEDURAL
+ if tex.type != "IMAGE" and tex.type != "NONE":
+ procedural_flag = True
+ image_filename = "PAT_%s" % string_strip_hyphen(bpy.path.clean_name(tex.name))
+ if image_filename:
+ if t.use_map_color_diffuse:
+ texture_dif = image_filename
+ # colvalue = t.default_value # UNUSED
+ t_dif = t
+ if t_dif.texture.pov.tex_gamma_enable:
+ img_gamma = " gamma %.3g " % t_dif.texture.pov.tex_gamma_value
+ if t.use_map_specular or t.use_map_raymir:
+ texture_spec = image_filename
+ # colvalue = t.default_value # UNUSED
+ t_spec = t
+ if t.use_map_normal:
+ texture_norm = image_filename
+ # colvalue = t.normal_factor/10 # UNUSED
+ # textNormName=tex.image.name + ".normal"
+ # was the above used? --MR
+ t_nor = t
+ if t.use_map_alpha:
+ texture_alpha = image_filename
+ # colvalue = t.alpha_factor * 10.0 # UNUSED
+ # textDispName=tex.image.name + ".displ"
+ # was the above used? --MR
+ t_alpha = t
+
+ # RASTER IMAGE
+ elif tex.type == "IMAGE" and tex.image and tex.pov.tex_pattern_type == "emulator":
+ procedural_flag = False
+ # PACKED
+ if tex.image.packed_file:
+ orig_image_filename = tex.image.filepath_raw
+ unpackedfilename = os.path.join(
+ preview_dir,
+ ("unpacked_img_" + (string_strip_hyphen(bpy.path.clean_name(tex.name)))),
+ )
+ if not os.path.exists(unpackedfilename):
+ # record which images that were newly copied and can be safely
+ # cleaned up
+ unpacked_images.append(unpackedfilename)
+ tex.image.filepath_raw = unpackedfilename
+ tex.image.save()
+ image_filename = unpackedfilename.replace("\\", "/")
+ # .replace("\\","/") to get only forward slashes as it's what POV prefers,
+ # even on windows
+ tex.image.filepath_raw = orig_image_filename
+ # FILE
+ else:
+ image_filename = path_image(tex.image)
+ # IMAGE SEQUENCE BEGINS
+ if image_filename:
+ if bpy.data.images[tex.image.name].source == "SEQUENCE":
+ korvaa = "." + str(tex.image_user.frame_offset + 1).zfill(3) + "."
+ image_filename = image_filename.replace(".001.", korvaa)
+ print(" seq debug ")
+ print(image_filename)
+ # IMAGE SEQUENCE ENDS
+ img_gamma = ""
+ if image_filename:
+ texdata = bpy.data.textures[t.texture]
+ if t.use_map_color_diffuse:
+ texture_dif = image_filename
+ # colvalue = t.default_value # UNUSED
+ t_dif = t
+ print(texdata)
+ if texdata.pov.tex_gamma_enable:
+ img_gamma = " gamma %.3g " % t_dif.texture.pov.tex_gamma_value
+ if t.use_map_specular or t.use_map_raymir:
+ texture_spec = image_filename
+ # colvalue = t.default_value # UNUSED
+ t_spec = t
+ if t.use_map_normal:
+ texture_norm = image_filename
+ # colvalue = t.normal_factor/10 # UNUSED
+ # textNormName=tex.image.name + ".normal"
+ # was the above used? --MR
+ t_nor = t
+ if t.use_map_alpha:
+ texture_alpha = image_filename
+ # colvalue = t.alpha_factor * 10.0 # UNUSED
+ # textDispName=tex.image.name + ".displ"
+ # was the above used? --MR
+ t_alpha = t
+
+ ####################################################################################
+
+ tab_write("\n")
+ # THIS AREA NEEDS TO LEAVE THE TEXTURE OPEN UNTIL ALL MAPS ARE WRITTEN DOWN.
+ # --MR
+ current_material_name = string_strip_hyphen(material_names_dictionary[mater.name])
+ local_material_names.append(current_material_name)
+ tab_write("\n#declare MAT_%s = \ntexture{\n" % current_material_name)
+ ################################################################################
+
+ if mater.pov.replacement_text != "":
+ tab_write("%s\n" % mater.pov.replacement_text)
+ #################################################################################
+ # XXX TODO: replace by new POV MINNAERT rather than aoi
+ if mater.pov.diffuse_shader == "MINNAERT":
+ tab_write("\n")
+ tab_write("aoi\n")
+ tab_write("texture_map {\n")
+ tab_write("[%.3g finish {diffuse %.3g}]\n" % (mater.darkness / 2.0, 2.0 - mater.darkness))
+ tab_write("[%.3g\n" % (1.0 - (mater.darkness / 2.0)))
+
+ if mater.pov.diffuse_shader == "FRESNEL":
+ # For FRESNEL diffuse in POV, we'll layer slope patterned textures
+ # with lamp vector as the slope vector and nest one slope per lamp
+ # into each texture map's entry.
+
+ c = 1
+ while c <= exported_lights_count:
+ tab_write("slope { lampTarget%s }\n" % (c))
+ tab_write("texture_map {\n")
+ # Diffuse Fresnel value and factor go up to five,
+ # other kind of values needed: used the number 5 below to remap
+ tab_write(
+ "[%.3g finish {diffuse %.3g}]\n"
+ % (
+ (5.0 - mater.diffuse_fresnel) / 5,
+ (mater.diffuse_intensity * ((5.0 - mater.diffuse_fresnel_factor) / 5)),
+ )
+ )
+ tab_write(
+ "[%.3g\n" % ((mater.diffuse_fresnel_factor / 5) * (mater.diffuse_fresnel / 5.0))
+ )
+ c += 1
+
+ # if shader is a 'FRESNEL' or 'MINNAERT': slope pigment pattern or aoi
+ # and texture map above, the rest below as one of its entry
+
+ if texture_spec != "" or texture_alpha != "":
+ if texture_spec != "":
+ # tab_write("\n")
+ tab_write("pigment_pattern {\n")
+
+ mapping_spec = img_map_transforms(t_spec)
+ if texture_spec and texture_spec.startswith("PAT_"):
+ tab_write("function{f%s(x,y,z).grey}\n" % texture_spec)
+ tab_write("%s\n" % mapping_spec)
+ else:
+
+ tab_write(
+ 'uv_mapping image_map{%s "%s" %s}\n'
+ % (image_format(texture_spec), texture_spec, img_map(t_spec))
+ )
+ tab_write("%s\n" % mapping_spec)
+ tab_write("}\n")
+ tab_write("texture_map {\n")
+ tab_write("[0 \n")
+
+ if texture_dif == "":
+ if texture_alpha != "":
+ tab_write("\n")
+
+ mapping_alpha = img_map_transforms(t_alpha)
+
+ if texture_alpha and texture_alpha.startswith("PAT_"):
+ tab_write("function{f%s(x,y,z).transmit}%s\n" % (texture_alpha, mapping_alpha))
+ else:
+
+ tab_write(
+ "pigment {pigment_pattern {uv_mapping image_map"
+ '{%s "%s" %s}%s'
+ % (
+ image_format(texture_alpha),
+ texture_alpha,
+ img_map(t_alpha),
+ mapping_alpha,
+ )
+ )
+ tab_write("}\n")
+ tab_write("pigment_map {\n")
+ tab_write("[0 color rgbft<0,0,0,1,1>]\n")
+ tab_write(
+ "[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n"
+ % (col[0], col[1], col[2], pov_filter, trans)
+ )
+ tab_write("}\n")
+ tab_write("}\n")
+
+ else:
+
+ tab_write(
+ "pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n"
+ % (col[0], col[1], col[2], pov_filter, trans)
+ )
+
+ if texture_spec != "":
+ # ref_level_bound 1 is no specular
+ tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=1)))
+
+ else:
+ # ref_level_bound 2 is translated spec
+ tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
+
+ else:
+ mapping_dif = img_map_transforms(t_dif)
+
+ if texture_alpha != "":
+ mapping_alpha = img_map_transforms(t_alpha)
+
+ tab_write("pigment {\n")
+ tab_write("pigment_pattern {\n")
+ if texture_alpha and texture_alpha.startswith("PAT_"):
+ tab_write("function{f%s(x,y,z).transmit}%s\n" % (texture_alpha, mapping_alpha))
+ else:
+ tab_write(
+ 'uv_mapping image_map{%s "%s" %s}%s}\n'
+ % (
+ image_format(texture_alpha),
+ texture_alpha,
+ img_map(t_alpha),
+ mapping_alpha,
+ )
+ )
+ tab_write("pigment_map {\n")
+ tab_write("[0 color rgbft<0,0,0,1,1>]\n")
+ # if texture_alpha and texture_alpha.startswith("PAT_"):
+ # tab_write("[1 pigment{%s}]\n" %texture_dif)
+ if texture_dif and not texture_dif.startswith("PAT_"):
+ tab_write(
+ '[1 uv_mapping image_map {%s "%s" %s} %s]\n'
+ % (
+ image_format(texture_dif),
+ texture_dif,
+ (img_gamma + img_map(t_dif)),
+ mapping_dif,
+ )
+ )
+ elif texture_dif and texture_dif.startswith("PAT_"):
+ tab_write("[1 %s]\n" % texture_dif)
+ tab_write("}\n")
+ tab_write("}\n")
+ if texture_alpha and texture_alpha.startswith("PAT_"):
+ tab_write("}\n")
+
+ else:
+ if texture_dif and texture_dif.startswith("PAT_"):
+ tab_write("pigment{%s}\n" % texture_dif)
+ else:
+ tab_write(
+ 'pigment {uv_mapping image_map {%s "%s" %s}%s}\n'
+ % (
+ image_format(texture_dif),
+ texture_dif,
+ (img_gamma + img_map(t_dif)),
+ mapping_dif,
+ )
+ )
+
+ if texture_spec != "":
+ # ref_level_bound 1 is no specular
+ tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=1)))
+
+ else:
+ # ref_level_bound 2 is translated specular
+ tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
+
+ ## scale 1 rotate y*0
+ # imageMap = ("{image_map {%s \"%s\" %s }\n" % \
+ # (image_format(textures),textures,img_map(t_dif)))
+ # tab_write("uv_mapping pigment %s} %s finish {%s}\n" % \
+ # (imageMap,mapping,safety(material_finish)))
+ # tab_write("pigment {uv_mapping image_map {%s \"%s\" %s}%s} " \
+ # "finish {%s}\n" % \
+ # (image_format(texture_dif), texture_dif, img_map(t_dif),
+ # mapping_dif, safety(material_finish)))
+ if texture_norm != "":
+ ## scale 1 rotate y*0
+
+ mapping_normal = img_map_transforms(t_nor)
+
+ if texture_norm and texture_norm.startswith("PAT_"):
+ tab_write(
+ "normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n"
+ % (texture_norm, (-t_nor.normal_factor * 9.5), mapping_normal)
+ )
+ else:
+ tab_write("normal {\n")
+ # XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
+ if (
+ mater.pov_raytrace_mirror.use
+ and mater.pov_raytrace_mirror.gloss_factor < 1.0
+ and not using_uberpov
+ ):
+ tab_write("average\n")
+ tab_write("normal_map{\n")
+ # 0.5 for entries below means a 50 percent mix
+ # between the micro normal and user bump map
+ # order seems indifferent as commutative
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (10 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write("[1.0 ") # Proceed with user bump...
+ tab_write(
+ "uv_mapping bump_map "
+ '{%s "%s" %s bump_size %.4g }%s'
+ % (
+ image_format(texture_norm),
+ texture_norm,
+ img_map(t_nor),
+ (-t_nor.normal_factor * 9.5),
+ mapping_normal,
+ )
+ )
+ # ...Then close its last entry and the the normal_map itself
+ if (
+ mater.pov_raytrace_mirror.use
+ and mater.pov_raytrace_mirror.gloss_factor < 1.0
+ and not using_uberpov
+ ):
+ tab_write("]}}\n")
+ else:
+ tab_write("]}\n")
+ if texture_spec != "":
+ tab_write("]\n")
+ ##################Second index for mapping specular max value###############
+ tab_write("[1 \n")
+
+ if texture_dif == "" and mater.pov.replacement_text == "":
+ if texture_alpha != "":
+ mapping_alpha = img_map_transforms(t_alpha)
+
+ if texture_alpha and texture_alpha.startswith("PAT_"):
+ tab_write("function{f%s(x,y,z).transmit %s}\n" % (texture_alpha, mapping_alpha))
+ else:
+ tab_write(
+ "pigment {pigment_pattern {uv_mapping image_map"
+ '{%s "%s" %s}%s}\n'
+ % (image_format(texture_alpha), texture_alpha, img_map(t_alpha), mapping_alpha)
+ )
+ tab_write("pigment_map {\n")
+ tab_write("[0 color rgbft<0,0,0,1,1>]\n")
+ tab_write(
+ "[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n"
+ % (col[0], col[1], col[2], pov_filter, trans)
+ )
+ tab_write("}\n")
+ tab_write("}\n")
+
+ else:
+ tab_write(
+ "pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n"
+ % (col[0], col[1], col[2], pov_filter, trans)
+ )
+
+ if texture_spec != "":
+ # ref_level_bound 3 is full specular
+ tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=3)))
+
+ if (
+ mater.pov_raytrace_mirror.use
+ and mater.pov_raytrace_mirror.gloss_factor < 1.0
+ and not using_uberpov
+ ):
+ tab_write("normal {\n")
+ tab_write("average\n")
+ tab_write("normal_map{\n")
+ # 0.5 for entries below means a 50 percent mix
+ # between the micro normal and user bump map
+ # order seems indifferent as commutative
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (10 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ # XXX IF USER BUMP_MAP
+ if texture_norm != "":
+ tab_write(
+ "[1.0 "
+ ) # Blurry reflection or not Proceed with user bump in either case...
+ tab_write(
+ "uv_mapping bump_map "
+ '{%s "%s" %s bump_size %.4g }%s]\n'
+ % (
+ image_format(texture_norm),
+ texture_norm,
+ img_map(t_nor),
+ (-t_nor.normal_factor * 9.5),
+ mapping_normal,
+ )
+ )
+ # ...Then close the normal_map itself if blurry reflection
+ if (
+ mater.pov_raytrace_mirror.use
+ and mater.pov_raytrace_mirror.gloss_factor < 1.0
+ and not using_uberpov
+ ):
+ tab_write("}}\n")
+ else:
+ tab_write("}\n")
+ elif colored_specular_found:
+ # ref_level_bound 1 is no specular
+ tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=1)))
+
+ else:
+ # ref_level_bound 2 is translated specular
+ tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
+
+ elif mater.pov.replacement_text == "":
+ mapping_dif = img_map_transforms(t_dif)
+
+ if texture_alpha != "":
+
+ mapping_alpha = img_map_transforms(t_alpha)
+
+ if texture_alpha and texture_alpha.startswith("PAT_"):
+ tab_write(
+ "pigment{pigment_pattern {function{f%s(x,y,z).transmit}%s}\n"
+ % (texture_alpha, mapping_alpha)
+ )
+ else:
+ tab_write(
+ "pigment {pigment_pattern {uv_mapping image_map"
+ '{%s "%s" %s}%s}\n'
+ % (image_format(texture_alpha), texture_alpha, img_map(t_alpha), mapping_alpha)
+ )
+ tab_write("pigment_map {\n")
+ tab_write("[0 color rgbft<0,0,0,1,1>]\n")
+ if texture_alpha and texture_alpha.startswith("PAT_"):
+ tab_write("[1 function{f%s(x,y,z).transmit}%s]\n" % (texture_alpha, mapping_alpha))
+ elif texture_dif and not texture_dif.startswith("PAT_"):
+ tab_write(
+ '[1 uv_mapping image_map {%s "%s" %s} %s]\n'
+ % (
+ image_format(texture_dif),
+ texture_dif,
+ (img_map(t_dif) + img_gamma),
+ mapping_dif,
+ )
+ )
+ elif texture_dif and texture_dif.startswith("PAT_"):
+ tab_write("[1 %s %s]\n" % (texture_dif, mapping_dif))
+ tab_write("}\n")
+ tab_write("}\n")
+
+ else:
+ if texture_dif and texture_dif.startswith("PAT_"):
+ tab_write("pigment{%s %s}\n" % (texture_dif, mapping_dif))
+ else:
+ tab_write("pigment {\n")
+ tab_write("uv_mapping image_map {\n")
+ # tab_write("%s \"%s\" %s}%s\n" % \
+ # (image_format(texture_dif), texture_dif,
+ # (img_gamma + img_map(t_dif)),mapping_dif))
+ tab_write('%s "%s" \n' % (image_format(texture_dif), texture_dif))
+ tab_write("%s\n" % (img_gamma + img_map(t_dif)))
+ tab_write("}\n")
+ tab_write("%s\n" % mapping_dif)
+ tab_write("}\n")
+
+ if texture_spec != "":
+ # ref_level_bound 3 is full specular
+ tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=3)))
+ else:
+ # ref_level_bound 2 is translated specular
+ tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
+
+ ## scale 1 rotate y*0
+ # imageMap = ("{image_map {%s \"%s\" %s }" % \
+ # (image_format(textures), textures,img_map(t_dif)))
+ # tab_write("\n\t\t\tuv_mapping pigment %s} %s finish {%s}" % \
+ # (imageMap, mapping, safety(material_finish)))
+ # tab_write("\n\t\t\tpigment {uv_mapping image_map " \
+ # "{%s \"%s\" %s}%s} finish {%s}" % \
+ # (image_format(texture_dif), texture_dif,img_map(t_dif),
+ # mapping_dif, safety(material_finish)))
+ if texture_norm != "" and mater.pov.replacement_text == "":
+
+ mapping_normal = img_map_transforms(t_nor)
+
+ if texture_norm and texture_norm.startswith("PAT_"):
+ tab_write(
+ "normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n"
+ % (texture_norm, (-t_nor.normal_factor * 9.5), mapping_normal)
+ )
+ else:
+ tab_write("normal {\n")
+ # XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
+ if (
+ mater.pov_raytrace_mirror.use
+ and mater.pov_raytrace_mirror.gloss_factor < 1.0
+ and not using_uberpov
+ ):
+ tab_write("average\n")
+ tab_write("normal_map{\n")
+ # 0.5 for entries below means a 50 percent mix
+ # between the micro normal and user bump map
+ # order seems indifferent as commutative
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (10 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n"
+ % (
+ (10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
+ (1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
+ )
+ ) # micronormals blurring
+ tab_write(
+ "[1.0 "
+ ) # Blurry reflection or not Proceed with user bump in either case...
+ tab_write(
+ "uv_mapping bump_map "
+ '{%s "%s" %s bump_size %.4g }%s]\n'
+ % (
+ image_format(texture_norm),
+ texture_norm,
+ img_map(t_nor),
+ (-t_nor.normal_factor * 9.5),
+ mapping_normal,
+ )
+ )
+ # ...Then close the normal_map itself if blurry reflection
+ if (
+ mater.pov_raytrace_mirror.use
+ and mater.pov_raytrace_mirror.gloss_factor < 1.0
+ and not using_uberpov
+ ):
+ tab_write("}}\n")
+ else:
+ tab_write("}\n")
+ if texture_spec != "" and mater.pov.replacement_text == "":
+ tab_write("]\n")
+
+ tab_write("}\n")
+
+ # End of slope/ior texture_map
+ if mater.pov.diffuse_shader == "MINNAERT" and mater.pov.replacement_text == "":
+ tab_write("]\n")
+ tab_write("}\n")
+ if mater.pov.diffuse_shader == "FRESNEL" and mater.pov.replacement_text == "":
+ c = 1
+ while c <= exported_lights_count:
+ tab_write("]\n")
+ tab_write("}\n")
+ c += 1
+
+ # Close first layer of POV "texture" (Blender material)
+ tab_write("}\n")
+
+ colored_specular_found = bool(
+ (mater.pov.specular_color.s > 0.0) and (mater.pov.diffuse_shader != "MINNAERT")
+ )
+
+ # Write another layered texture using invisible diffuse and metallic trick
+ # to emulate colored specular highlights
+ special_texture_found = False
+ tmpidx = -1
+ for t in mater.pov_texture_slots:
+ tmpidx += 1
+ # index = mater.pov.active_texture_index
+ slot = mater.pov_texture_slots[tmpidx] # [index]
+ povtex = slot.texture # slot.name
+ tex = bpy.data.textures[povtex]
+ # Specular mapped textures would conflict with colored specular
+ # because POV can't layer over or under pigment patterned textures
+ special_texture_found = bool(
+ t
+ and t.use
+ and ((tex.type == "IMAGE" and tex.image) or tex.type != "IMAGE")
+ and (t.use_map_specular or t.use_map_raymir)
+ )
+ if colored_specular_found and not special_texture_found:
+ if comments:
+ tab_write(" // colored highlights with a stransparent metallic layer\n")
+ else:
+ tab_write("\n")
+
+ tab_write("texture {\n")
+ tab_write(
+ "pigment {rgbft<%.3g, %.3g, %.3g, 0, 1>}\n"
+ % (
+ mater.pov.specular_color[0],
+ mater.pov.specular_color[1],
+ mater.pov.specular_color[2],
+ )
+ )
+ tab_write(
+ "finish {%s}\n" % (safety(material_finish, ref_level_bound=2))
+ ) # ref_level_bound 2 is translated spec
+
+ texture_norm = ""
+ for t in mater.pov_texture_slots:
+
+ if t and tex.pov.tex_pattern_type != "emulator":
+ procedural_flag = True
+ image_filename = string_strip_hyphen(bpy.path.clean_name(tex.name))
+ if (
+ t
+ and tex.type == "IMAGE"
+ and t.use
+ and tex.image
+ and tex.pov.tex_pattern_type == "emulator"
+ ):
+ procedural_flag = False
+ image_filename = path_image(tex.image)
+ img_gamma = ""
+ if image_filename:
+ if t.use_map_normal:
+ texture_norm = image_filename
+ # colvalue = t.normal_factor/10 # UNUSED XXX *-9.5 !
+ # textNormName=tex.image.name + ".normal"
+ # was the above used? --MR
+ t_nor = t
+ if procedural_flag:
+ tab_write(
+ "normal{function"
+ "{f%s(x,y,z).grey} bump_size %.4g}\n"
+ % (texture_norm, (-t_nor.normal_factor * 9.5))
+ )
+ else:
+ tab_write(
+ "normal {uv_mapping bump_map "
+ '{%s "%s" %s bump_size %.4g }%s}\n'
+ % (
+ image_format(texture_norm),
+ texture_norm,
+ img_map(t_nor),
+ (-t_nor.normal_factor * 9.5),
+ mapping_normal,
+ )
+ )
+
+ tab_write("}\n") # THEN IT CAN CLOSE LAST LAYER OF TEXTURE
diff --git a/render_povray/texturing_gui.py b/render_povray/texturing_gui.py
new file mode 100755
index 00000000..ad889f43
--- /dev/null
+++ b/render_povray/texturing_gui.py
@@ -0,0 +1,1251 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""User interface for texturing tools."""
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import (
+ Operator,
+ Menu,
+ UIList,
+ Panel,
+ Brush,
+ Material,
+ Light,
+ World,
+ ParticleSettings,
+ FreestyleLineStyle,
+)
+
+# from .ui import TextureButtonsPanel
+
+from .shading_properties import pov_context_tex_datablock
+from bl_ui.properties_paint_common import brush_texture_settings
+
+# Example of wrapping every class 'as is'
+from bl_ui import properties_texture
+
+# unused, replaced by pov_context_tex_datablock (no way to use?):
+# from bl_ui.properties_texture import context_tex_datablock
+# from bl_ui.properties_texture import texture_filter_common #unused yet?
+
+for member in dir(properties_texture):
+ subclass = getattr(properties_texture, member)
+ if hasattr(subclass, "COMPAT_ENGINES"):
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+del properties_texture
+
+
+class TextureButtonsPanel:
+ """Use this class to define buttons from the texture tab properties."""
+
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "texture"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ tex = context.texture
+ rd = context.scene.render
+ return tex and (rd.engine in cls.COMPAT_ENGINES)
+
+
+class TEXTURE_MT_POV_specials(Menu):
+ """Use this class to define pov texture slot operations buttons."""
+
+ bl_label = "Texture Specials"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("texture.slot_copy", icon='COPYDOWN')
+ layout.operator("texture.slot_paste", icon='PASTEDOWN')
+
+
+class WORLD_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
+ """Use this class to show pov texture slots list.""" # XXX Not used yet
+
+ index: bpy.props.IntProperty(name='index')
+ # should active_propname be index or..?
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ world = context.scene.world # .pov
+ active_data = world.pov
+ # tex = context.texture #may be needed later?
+
+ # We could write some code to decide which icon to use here...
+ # custom_icon = 'TEXTURE'
+
+ # ob = data
+ slot = item
+ # ma = slot.name
+ # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ # You should always start your row layout by a label (icon + text), or a non-embossed text field,
+ # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
+ # We use icon_value of label, as our given icon is an integer value, not an enum ID.
+ # Note "data" names should never be translated!
+ if slot:
+ layout.prop(item, "texture", text="", emboss=False, icon='TEXTURE')
+ else:
+ layout.label(text="New", translate=False, icon_value=icon)
+ # 'GRID' layout type should be as compact as possible (typically a single icon!).
+ elif self.layout_type in {'GRID'}:
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
+
+
+class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
+ """Use this class to show pov texture slots list."""
+
+ # texture_slots:
+ index: bpy.props.IntProperty(name='index')
+ # foo = random prop
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ # ob = data
+ slot = item
+ # ma = slot.name
+ # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ # You should always start your row layout by a label (icon + text), or a non-embossed text field,
+ # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
+ # We use icon_value of label, as our given icon is an integer value, not an enum ID.
+ # Note "data" names should never be translated!
+ if slot:
+ layout.prop(item, "texture", text="", emboss=False, icon='TEXTURE')
+ else:
+ layout.label(text="New", translate=False, icon_value=icon)
+ # 'GRID' layout type should be as compact as possible (typically a single icon!).
+ elif self.layout_type in {'GRID'}:
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
+
+
+class TEXTURE_PT_context(TextureButtonsPanel, Panel):
+ """Rewrite of this existing class to modify it."""
+
+ bl_label = ""
+ bl_context = "texture"
+ bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'POVRAY_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+ # register but not unregistered because
+ # the modified parts concern only POVRAY_RENDER
+ @classmethod
+ def poll(cls, context):
+ return (
+ context.scene.texture_context
+ not in ('MATERIAL', 'WORLD', 'LIGHT', 'PARTICLES', 'LINESTYLE')
+ or context.scene.render.engine != 'POVRAY_RENDER'
+ )
+
+ def draw(self, context):
+ layout = self.layout
+ tex = context.texture
+ space = context.space_data
+ pin_id = space.pin_id
+ use_pin_id = space.use_pin_id
+ user = context.texture_user
+
+ col = layout.column()
+
+ if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
+ pin_id = None
+
+ if not pin_id:
+ col.template_texture_user()
+
+ if user or pin_id:
+ col.separator()
+
+ if pin_id:
+ col.template_ID(space, "pin_id")
+ else:
+ propname = context.texture_user_property.identifier
+ col.template_ID(user, propname, new="texture.new")
+
+ if tex:
+ col.separator()
+
+ split = col.split(factor=0.2)
+ split.label(text="Type")
+ split.prop(tex, "type", text="")
+
+
+class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel):
+ """Use this class to show pov texture context buttons."""
+
+ bl_label = ""
+ bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ return engine in cls.COMPAT_ENGINES
+ # if not (hasattr(context, "pov_texture_slot") or hasattr(context, "texture_node")):
+ # return False
+ return (
+ context.material
+ or context.scene.world
+ or context.light
+ or context.texture
+ or context.line_style
+ or context.particle_system
+ or isinstance(context.space_data.pin_id, ParticleSettings)
+ or context.texture_user
+ ) and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ mat = context.view_layer.objects.active.active_material
+ wld = context.scene.world
+
+ layout.prop(scene, "texture_context", expand=True)
+ if scene.texture_context == 'MATERIAL' and mat is not None:
+
+ row = layout.row()
+ row.template_list(
+ "MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist",
+ "",
+ mat,
+ "pov_texture_slots",
+ mat.pov,
+ "active_texture_index",
+ rows=2,
+ maxrows=16,
+ type="DEFAULT",
+ )
+ col = row.column(align=True)
+ col.operator("pov.textureslotadd", icon='ADD', text='')
+ col.operator("pov.textureslotremove", icon='REMOVE', text='')
+ # XXX todo: recreate for pov_texture_slots?
+ # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
+ # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
+ col.separator()
+
+ if mat.pov_texture_slots:
+ index = mat.pov.active_texture_index
+ slot = mat.pov_texture_slots[index]
+ povtex = slot.texture # slot.name
+ tex = bpy.data.textures[povtex]
+ col.prop(tex, 'use_fake_user', text='')
+ # layout.label(text='Linked Texture data browser:')
+ # propname = slot.texture_search
+ # if slot.texture was a pointer to texture data rather than just a name string:
+ # layout.template_ID(povtex, "texture", new="texture.new")
+
+ layout.prop_search(
+ slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE'
+ )
+ try:
+ bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[
+ slot.texture_search
+ ]
+ bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
+ slot.texture_search
+ ]
+ except KeyError:
+ # texture not hand-linked by user
+ pass
+
+ if tex:
+ layout.separator()
+ split = layout.split(factor=0.2)
+ split.label(text="Type")
+ split.prop(tex, "type", text="")
+
+ # else:
+ # for i in range(18): # length of material texture slots
+ # mat.pov_texture_slots.add()
+ elif scene.texture_context == 'WORLD' and wld is not None:
+
+ row = layout.row()
+ row.template_list(
+ "WORLD_TEXTURE_SLOTS_UL_POV_layerlist",
+ "",
+ wld,
+ "pov_texture_slots",
+ wld.pov,
+ "active_texture_index",
+ rows=2,
+ maxrows=16,
+ type="DEFAULT",
+ )
+ col = row.column(align=True)
+ col.operator("pov.textureslotadd", icon='ADD', text='')
+ col.operator("pov.textureslotremove", icon='REMOVE', text='')
+
+ # todo: recreate for pov_texture_slots?
+ # col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
+ # col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
+ col.separator()
+
+ if wld.pov_texture_slots:
+ index = wld.pov.active_texture_index
+ slot = wld.pov_texture_slots[index]
+ povtex = slot.texture # slot.name
+ tex = bpy.data.textures[povtex]
+ col.prop(tex, 'use_fake_user', text='')
+ # layout.label(text='Linked Texture data browser:')
+ propname = slot.texture_search
+ # if slot.texture was a pointer to texture data rather than just a name string:
+ # layout.template_ID(povtex, "texture", new="texture.new")
+
+ layout.prop_search(
+ slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE'
+ )
+ try:
+ bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[
+ slot.texture_search
+ ]
+ bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[
+ slot.texture_search
+ ]
+ except KeyError:
+ # texture not hand-linked by user
+ pass
+
+ if tex:
+ layout.separator()
+ split = layout.split(factor=0.2)
+ split.label(text="Type")
+ split.prop(tex, "type", text="")
+
+
+# Commented out below is a reminder of what existed in Blender Internal
+# attributes need to be recreated
+'''
+ slot = getattr(context, "texture_slot", None)
+ node = getattr(context, "texture_node", None)
+ space = context.space_data
+
+ #attempt at replacing removed space_data
+ mtl = getattr(context, "material", None)
+ if mtl != None:
+ spacedependant = mtl
+ wld = getattr(context, "world", None)
+ if wld != None:
+ spacedependant = wld
+ lgt = getattr(context, "light", None)
+ if lgt != None:
+ spacedependant = lgt
+
+
+ #idblock = context.particle_system.settings
+
+ tex = getattr(context, "texture", None)
+ if tex != None:
+ spacedependant = tex
+
+
+
+ scene = context.scene
+ idblock = scene.pov#pov_context_tex_datablock(context)
+ pin_id = space.pin_id
+
+ #spacedependant.use_limited_texture_context = True
+
+ if space.use_pin_id and not isinstance(pin_id, Texture):
+ idblock = id_tex_datablock(pin_id)
+ pin_id = None
+
+ if not space.use_pin_id:
+ layout.row().prop(spacedependant, "texture_context", expand=True)
+ pin_id = None
+
+ if spacedependant.texture_context == 'OTHER':
+ if not pin_id:
+ layout.template_texture_user()
+ user = context.texture_user
+ if user or pin_id:
+ layout.separator()
+
+ row = layout.row()
+
+ if pin_id:
+ row.template_ID(space, "pin_id")
+ else:
+ propname = context.texture_user_property.identifier
+ row.template_ID(user, propname, new="texture.new")
+
+ if tex:
+ split = layout.split(factor=0.2)
+ if tex.use_nodes:
+ if slot:
+ split.label(text="Output:")
+ split.prop(slot, "output_node", text="")
+ else:
+ split.label(text="Type:")
+ split.prop(tex, "type", text="")
+ return
+
+ tex_collection = (pin_id is None) and (node is None) and (spacedependant.texture_context not in ('LINESTYLE','OTHER'))
+
+ if tex_collection:
+
+ pov = getattr(context, "pov", None)
+ active_texture_index = getattr(spacedependant, "active_texture_index", None)
+ print (pov)
+ print(idblock)
+ print(active_texture_index)
+ row = layout.row()
+
+ row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots",
+ idblock, "active_texture_index", rows=2, maxrows=16, type="DEFAULT")
+
+ # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
+ # world.texture_slots, world, "active_texture_index", rows=2)
+
+ col = row.column(align=True)
+ col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
+ col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
+ col.menu("TEXTURE_MT_POV_specials", icon='DOWNARROW_HLT', text="")
+
+ if tex_collection:
+ layout.template_ID(idblock, "active_texture", new="texture.new")
+ elif node:
+ layout.template_ID(node, "texture", new="texture.new")
+ elif idblock:
+ layout.template_ID(idblock, "texture", new="texture.new")
+
+ if pin_id:
+ layout.template_ID(space, "pin_id")
+
+ if tex:
+ split = layout.split(factor=0.2)
+ if tex.use_nodes:
+ if slot:
+ split.label(text="Output:")
+ split.prop(slot, "output_node", text="")
+ else:
+ split.label(text="Type:")
+'''
+
+
+class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
+ """Use this class to show pov color ramps."""
+
+ bl_label = "Colors"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ tex = context.texture
+
+ layout.prop(tex, "use_color_ramp", text="Ramp")
+ if tex.use_color_ramp:
+ layout.template_color_ramp(tex, "color_ramp", expand=True)
+
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="RGB Multiply:")
+ sub = col.column(align=True)
+ sub.prop(tex, "factor_red", text="R")
+ sub.prop(tex, "factor_green", text="G")
+ sub.prop(tex, "factor_blue", text="B")
+
+ col = split.column()
+ col.label(text="Adjust:")
+ col.prop(tex, "intensity")
+ col.prop(tex, "contrast")
+ col.prop(tex, "saturation")
+
+ col = layout.column()
+ col.prop(tex, "use_clamp", text="Clamp")
+
+
+# Texture Slot Panels #
+
+
+class TEXTURE_OT_POV_texture_slot_add(Operator):
+ """Use this class for the add texture slot button."""
+
+ bl_idname = "pov.textureslotadd"
+ bl_label = "Add"
+ bl_description = "Add texture_slot"
+ bl_options = {'REGISTER', 'UNDO'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def execute(self, context):
+ idblock = pov_context_tex_datablock(context)
+ tex = bpy.data.textures.new(name='Texture', type='IMAGE')
+ # tex.use_fake_user = True
+ # mat = context.view_layer.objects.active.active_material
+ slot = idblock.pov_texture_slots.add()
+ slot.name = tex.name
+ slot.texture = tex.name
+ slot.texture_search = tex.name
+ # Switch paint brush and paint brush mask
+ # to this texture so settings remain contextual
+ bpy.context.tool_settings.image_paint.brush.texture = tex
+ bpy.context.tool_settings.image_paint.brush.mask_texture = tex
+ idblock.pov.active_texture_index = len(idblock.pov_texture_slots) - 1
+
+ # for area in bpy.context.screen.areas:
+ # if area.type in ['PROPERTIES']:
+ # area.tag_redraw()
+
+ return {'FINISHED'}
+
+
+class TEXTURE_OT_POV_texture_slot_remove(Operator):
+ """Use this class for the remove texture slot button."""
+
+ bl_idname = "pov.textureslotremove"
+ bl_label = "Remove"
+ bl_description = "Remove texture_slot"
+ bl_options = {'REGISTER', 'UNDO'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def execute(self, context):
+ idblock = pov_context_tex_datablock(context)
+ # mat = context.view_layer.objects.active.active_material
+ # tex_slot = idblock.pov_texture_slots.remove(idblock.pov.active_texture_index) # not used
+ if idblock.pov.active_texture_index > 0:
+ idblock.pov.active_texture_index -= 1
+ try:
+ tex = idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
+ except IndexError:
+ # No more slots
+ return {'FINISHED'}
+ # Switch paint brush to previous texture so settings remain contextual
+ # if 'tex' in locals(): # Would test is the tex variable is assigned / exists
+ bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
+ bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
+
+ return {'FINISHED'}
+
+
+class TextureSlotPanel(TextureButtonsPanel):
+ """Use this class to show pov texture slots panel."""
+
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ if not hasattr(context, "pov_texture_slot"):
+ return False
+
+ engine = context.scene.render.engine
+ # return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES)
+ return TextureButtonsPanel.poll(context) and (engine in cls.COMPAT_ENGINES)
+
+
+class TEXTURE_PT_POV_type(TextureButtonsPanel, Panel):
+ """Use this class to define pov texture type buttons."""
+
+ bl_label = "POV Textures"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ bl_options = {'HIDE_HEADER'}
+
+ def draw(self, context):
+ layout = self.layout
+ # world = context.world # unused
+ tex = context.texture
+
+ split = layout.split(factor=0.2)
+ split.label(text="Pattern")
+ split.prop(tex.pov, "tex_pattern_type", text="")
+
+ # row = layout.row()
+ # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
+ # world.texture_slots, world, "active_texture_index")
+
+
+class TEXTURE_PT_POV_preview(TextureButtonsPanel, Panel):
+ """Use this class to define pov texture preview panel."""
+
+ bl_label = "Preview"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ bl_options = {'HIDE_HEADER'}
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.scene.render.engine
+ if not hasattr(context, "pov_texture_slot"):
+ return False
+ tex = context.texture
+ # mat = bpy.context.active_object.active_material #unused
+ return tex and (tex.pov.tex_pattern_type != 'emulator') and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ tex = context.texture
+ slot = getattr(context, "pov_texture_slot", None)
+ # idblock = pov_context_tex_datablock(context) # unused
+ layout = self.layout
+ # if idblock:
+ # layout.template_preview(tex, parent=idblock, slot=slot)
+ if tex.pov.tex_pattern_type != 'emulator':
+ layout.operator("tex.preview_update")
+ else:
+ layout.template_preview(tex, slot=slot)
+
+
+class TEXTURE_PT_POV_parameters(TextureButtonsPanel, Panel):
+ """Use this class to define pov texture pattern buttons."""
+
+ bl_label = "POV Pattern Options"
+ bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw(self, context):
+ # mat = bpy.context.active_object.active_material # Unused
+ layout = self.layout
+ tex = context.texture
+ align = True
+ if tex is not None and tex.pov.tex_pattern_type != 'emulator':
+ if tex.pov.tex_pattern_type == 'agate':
+ layout.prop(tex.pov, "modifier_turbulence", text="Agate Turbulence")
+ if tex.pov.tex_pattern_type in {'spiral1', 'spiral2'}:
+ layout.prop(tex.pov, "modifier_numbers", text="Number of arms")
+ if tex.pov.tex_pattern_type == 'tiling':
+ layout.prop(tex.pov, "modifier_numbers", text="Pattern number")
+ if tex.pov.tex_pattern_type == 'magnet':
+ layout.prop(tex.pov, "magnet_style", text="Magnet style")
+ if tex.pov.tex_pattern_type == 'quilted':
+ row = layout.row(align=align)
+ row.prop(tex.pov, "modifier_control0", text="Control0")
+ row.prop(tex.pov, "modifier_control1", text="Control1")
+ if tex.pov.tex_pattern_type == 'brick':
+ col = layout.column(align=align)
+ row = col.row()
+ row.prop(tex.pov, "brick_size_x", text="Brick size X")
+ row.prop(tex.pov, "brick_size_y", text="Brick size Y")
+ row = col.row()
+ row.prop(tex.pov, "brick_size_z", text="Brick size Z")
+ row.prop(tex.pov, "brick_mortar", text="Brick mortar")
+ if tex.pov.tex_pattern_type in {'julia', 'mandel', 'magnet'}:
+ col = layout.column(align=align)
+ if tex.pov.tex_pattern_type == 'julia':
+ row = col.row()
+ row.prop(tex.pov, "julia_complex_1", text="Complex 1")
+ row.prop(tex.pov, "julia_complex_2", text="Complex 2")
+ if tex.pov.tex_pattern_type == 'magnet' and tex.pov.magnet_style == 'julia':
+ row = col.row()
+ row.prop(tex.pov, "julia_complex_1", text="Complex 1")
+ row.prop(tex.pov, "julia_complex_2", text="Complex 2")
+ row = col.row()
+ if tex.pov.tex_pattern_type in {'julia', 'mandel'}:
+ row.prop(tex.pov, "f_exponent", text="Exponent")
+ if tex.pov.tex_pattern_type == 'magnet':
+ row.prop(tex.pov, "magnet_type", text="Type")
+ row.prop(tex.pov, "f_iter", text="Iterations")
+ row = col.row()
+ row.prop(tex.pov, "f_ior", text="Interior")
+ row.prop(tex.pov, "f_ior_fac", text="Factor I")
+ row = col.row()
+ row.prop(tex.pov, "f_eor", text="Exterior")
+ row.prop(tex.pov, "f_eor_fac", text="Factor E")
+ if tex.pov.tex_pattern_type == 'gradient':
+ layout.label(text="Gradient orientation:")
+ column_flow = layout.column_flow(columns=3, align=True)
+ column_flow.prop(tex.pov, "grad_orient_x", text="X")
+ column_flow.prop(tex.pov, "grad_orient_y", text="Y")
+ column_flow.prop(tex.pov, "grad_orient_z", text="Z")
+ if tex.pov.tex_pattern_type == 'pavement':
+ layout.prop(tex.pov, "pave_sides", text="Pavement:number of sides")
+ col = layout.column(align=align)
+ column_flow = col.column_flow(columns=3, align=True)
+ column_flow.prop(tex.pov, "pave_tiles", text="Tiles")
+ if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 6:
+ column_flow.prop(tex.pov, "pave_pat_35", text="Pattern")
+ if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 5:
+ column_flow.prop(tex.pov, "pave_pat_22", text="Pattern")
+ if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 5:
+ column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
+ if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 6:
+ column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
+ if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 4:
+ column_flow.prop(tex.pov, "pave_pat_7", text="Pattern")
+ if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 4:
+ column_flow.prop(tex.pov, "pave_pat_5", text="Pattern")
+ if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 5:
+ column_flow.prop(tex.pov, "pave_pat_4", text="Pattern")
+ if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 3:
+ column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
+ if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 4:
+ column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
+ if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 3:
+ column_flow.prop(tex.pov, "pave_pat_2", text="Pattern")
+ if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 6:
+ column_flow.label(text="!!! 5 tiles!")
+ column_flow.prop(tex.pov, "pave_form", text="Form")
+ if tex.pov.tex_pattern_type == 'function':
+ layout.prop(tex.pov, "func_list", text="Functions")
+ if tex.pov.tex_pattern_type == 'function' and tex.pov.func_list != "NONE":
+ func = None
+ if tex.pov.func_list in {"f_noise3d", "f_ph", "f_r", "f_th"}:
+ func = 0
+ if tex.pov.func_list in {
+ "f_comma",
+ "f_crossed_trough",
+ "f_cubic_saddle",
+ "f_cushion",
+ "f_devils_curve",
+ "f_enneper",
+ "f_glob",
+ "f_heart",
+ "f_hex_x",
+ "f_hex_y",
+ "f_hunt_surface",
+ "f_klein_bottle",
+ "f_kummer_surface_v1",
+ "f_lemniscate_of_gerono",
+ "f_mitre",
+ "f_nodal_cubic",
+ "f_noise_generator",
+ "f_odd",
+ "f_paraboloid",
+ "f_pillow",
+ "f_piriform",
+ "f_quantum",
+ "f_quartic_paraboloid",
+ "f_quartic_saddle",
+ "f_sphere",
+ "f_steiners_roman",
+ "f_torus_gumdrop",
+ "f_umbrella",
+ }:
+ func = 1
+ if tex.pov.func_list in {
+ "f_bicorn",
+ "f_bifolia",
+ "f_boy_surface",
+ "f_superellipsoid",
+ "f_torus",
+ }:
+ func = 2
+ if tex.pov.func_list in {
+ "f_ellipsoid",
+ "f_folium_surface",
+ "f_hyperbolic_torus",
+ "f_kampyle_of_eudoxus",
+ "f_parabolic_torus",
+ "f_quartic_cylinder",
+ "f_torus2",
+ }:
+ func = 3
+ if tex.pov.func_list in {
+ "f_blob2",
+ "f_cross_ellipsoids",
+ "f_flange_cover",
+ "f_isect_ellipsoids",
+ "f_kummer_surface_v2",
+ "f_ovals_of_cassini",
+ "f_rounded_box",
+ "f_spikes_2d",
+ "f_strophoid",
+ }:
+ func = 4
+ if tex.pov.func_list in {
+ "f_algbr_cyl1",
+ "f_algbr_cyl2",
+ "f_algbr_cyl3",
+ "f_algbr_cyl4",
+ "f_blob",
+ "f_mesh1",
+ "f_poly4",
+ "f_spikes",
+ }:
+ func = 5
+ if tex.pov.func_list in {
+ "f_devils_curve_2d",
+ "f_dupin_cyclid",
+ "f_folium_surface_2d",
+ "f_hetero_mf",
+ "f_kampyle_of_eudoxus_2d",
+ "f_lemniscate_of_gerono_2d",
+ "f_polytubes",
+ "f_ridge",
+ "f_ridged_mf",
+ "f_spiral",
+ "f_witch_of_agnesi",
+ }:
+ func = 6
+ if tex.pov.func_list in {"f_helix1", "f_helix2", "f_piriform_2d", "f_strophoid_2d"}:
+ func = 7
+ if tex.pov.func_list == "f_helical_torus":
+ func = 8
+ column_flow = layout.column_flow(columns=3, align=True)
+ column_flow.label(text="X")
+ column_flow.prop(tex.pov, "func_plus_x", text="")
+ column_flow.prop(tex.pov, "func_x", text="Value")
+ column_flow = layout.column_flow(columns=3, align=True)
+ column_flow.label(text="Y")
+ column_flow.prop(tex.pov, "func_plus_y", text="")
+ column_flow.prop(tex.pov, "func_y", text="Value")
+ column_flow = layout.column_flow(columns=3, align=True)
+ column_flow.label(text="Z")
+ column_flow.prop(tex.pov, "func_plus_z", text="")
+ column_flow.prop(tex.pov, "func_z", text="Value")
+ row = layout.row(align=align)
+ if func > 0:
+ row.prop(tex.pov, "func_P0", text="P0")
+ if func > 1:
+ row.prop(tex.pov, "func_P1", text="P1")
+ row = layout.row(align=align)
+ if func > 2:
+ row.prop(tex.pov, "func_P2", text="P2")
+ if func > 3:
+ row.prop(tex.pov, "func_P3", text="P3")
+ row = layout.row(align=align)
+ if func > 4:
+ row.prop(tex.pov, "func_P4", text="P4")
+ if func > 5:
+ row.prop(tex.pov, "func_P5", text="P5")
+ row = layout.row(align=align)
+ if func > 6:
+ row.prop(tex.pov, "func_P6", text="P6")
+ if func > 7:
+ row.prop(tex.pov, "func_P7", text="P7")
+ row = layout.row(align=align)
+ row.prop(tex.pov, "func_P8", text="P8")
+ row.prop(tex.pov, "func_P9", text="P9")
+ ###################################################End Patterns############################
+
+ layout.prop(tex.pov, "warp_types", text="Warp types") # warp
+ if tex.pov.warp_types == "TOROIDAL":
+ layout.prop(tex.pov, "warp_tor_major_radius", text="Major radius")
+ if tex.pov.warp_types not in {"CUBIC", "NONE"}:
+ layout.prop(tex.pov, "warp_orientation", text="Warp orientation")
+ col = layout.column(align=align)
+ row = col.row()
+ row.prop(tex.pov, "warp_dist_exp", text="Distance exponent")
+ row = col.row()
+ row.prop(tex.pov, "modifier_frequency", text="Frequency")
+ row.prop(tex.pov, "modifier_phase", text="Phase")
+
+ row = layout.row()
+
+ row.label(text="Offset:")
+ row.label(text="Scale:")
+ row.label(text="Rotate:")
+ col = layout.column(align=align)
+ row = col.row()
+ row.prop(tex.pov, "tex_mov_x", text="X")
+ row.prop(tex.pov, "tex_scale_x", text="X")
+ row.prop(tex.pov, "tex_rot_x", text="X")
+ row = col.row()
+ row.prop(tex.pov, "tex_mov_y", text="Y")
+ row.prop(tex.pov, "tex_scale_y", text="Y")
+ row.prop(tex.pov, "tex_rot_y", text="Y")
+ row = col.row()
+ row.prop(tex.pov, "tex_mov_z", text="Z")
+ row.prop(tex.pov, "tex_scale_z", text="Z")
+ row.prop(tex.pov, "tex_rot_z", text="Z")
+ row = layout.row()
+
+ row.label(text="Turbulence:")
+ col = layout.column(align=align)
+ row = col.row()
+ row.prop(tex.pov, "warp_turbulence_x", text="X")
+ row.prop(tex.pov, "modifier_octaves", text="Octaves")
+ row = col.row()
+ row.prop(tex.pov, "warp_turbulence_y", text="Y")
+ row.prop(tex.pov, "modifier_lambda", text="Lambda")
+ row = col.row()
+ row.prop(tex.pov, "warp_turbulence_z", text="Z")
+ row.prop(tex.pov, "modifier_omega", text="Omega")
+
+
+class TEXTURE_PT_POV_mapping(TextureSlotPanel, Panel):
+ """Use this class to define POV texture mapping buttons."""
+
+ bl_label = "Mapping"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+
+ @classmethod
+ def poll(cls, context):
+ idblock = pov_context_tex_datablock(context)
+ if isinstance(idblock, Brush) and not context.sculpt_object:
+ return False
+
+ if not getattr(context, "texture_slot", None):
+ return False
+
+ engine = context.scene.render.engine
+ return engine in cls.COMPAT_ENGINES
+
+ def draw(self, context):
+ layout = self.layout
+
+ idblock = pov_context_tex_datablock(context)
+ mat = bpy.context.active_object.active_material
+ # tex = context.texture_slot
+ tex = mat.pov_texture_slots[mat.active_texture_index]
+ if not isinstance(idblock, Brush):
+ split = layout.split(percentage=0.3)
+ col = split.column()
+ col.label(text="Coordinates:")
+ col = split.column()
+ col.prop(tex, "texture_coords", text="")
+
+ if tex.texture_coords == 'ORCO':
+ """
+ ob = context.object
+ if ob and ob.type == 'MESH':
+ split = layout.split(percentage=0.3)
+ split.label(text="Mesh:")
+ split.prop(ob.data, "texco_mesh", text="")
+ """
+ elif tex.texture_coords == 'UV':
+ split = layout.split(percentage=0.3)
+ split.label(text="Map:")
+ ob = context.object
+ if ob and ob.type == 'MESH':
+ split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="")
+ else:
+ split.prop(tex, "uv_layer", text="")
+
+ elif tex.texture_coords == 'OBJECT':
+ split = layout.split(percentage=0.3)
+ split.label(text="Object:")
+ split.prop(tex, "object", text="")
+
+ elif tex.texture_coords == 'ALONG_STROKE':
+ split = layout.split(percentage=0.3)
+ split.label(text="Use Tips:")
+ split.prop(tex, "use_tips", text="")
+
+ if isinstance(idblock, Brush):
+ if context.sculpt_object or context.image_paint_object:
+ brush_texture_settings(layout, idblock, context.sculpt_object)
+ else:
+ if isinstance(idblock, FreestyleLineStyle):
+ split = layout.split(percentage=0.3)
+ split.label(text="Projection:")
+ split.prop(tex, "mapping", text="")
+
+ split = layout.split(percentage=0.3)
+ split.separator()
+ row = split.row()
+ row.prop(tex, "mapping_x", text="")
+ row.prop(tex, "mapping_y", text="")
+ row.prop(tex, "mapping_z", text="")
+
+ elif isinstance(idblock, Material):
+ split = layout.split(percentage=0.3)
+ split.label(text="Projection:")
+ split.prop(tex, "mapping", text="")
+
+ split = layout.split()
+
+ col = split.column()
+ if tex.texture_coords in {'ORCO', 'UV'}:
+ col.prop(tex, "use_from_dupli")
+ if idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO':
+ col.prop(tex, "use_map_to_bounds")
+ elif tex.texture_coords == 'OBJECT':
+ col.prop(tex, "use_from_original")
+ if idblock.type == 'VOLUME':
+ col.prop(tex, "use_map_to_bounds")
+ else:
+ col.label()
+
+ col = split.column()
+ row = col.row()
+ row.prop(tex, "mapping_x", text="")
+ row.prop(tex, "mapping_y", text="")
+ row.prop(tex, "mapping_z", text="")
+
+ row = layout.row()
+ row.column().prop(tex, "offset")
+ row.column().prop(tex, "scale")
+
+
+class TEXTURE_PT_POV_influence(TextureSlotPanel, Panel):
+ """Use this class to define pov texture influence buttons."""
+
+ bl_label = "Influence"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ # bl_context = 'texture'
+ @classmethod
+ def poll(cls, context):
+ idblock = pov_context_tex_datablock(context)
+ if (
+ # isinstance(idblock, Brush) and # Brush used for everything since 2.8
+ context.scene.texture_context
+ == 'OTHER'
+ ): # XXX replace by isinstance(idblock, bpy.types.Brush) and ...
+ return False
+
+ # Specify below also for pov_world_texture_slots, lights etc.
+ # to display for various types of slots but only when any
+ if not getattr(idblock, "pov_texture_slots", None):
+ return False
+
+ engine = context.scene.render.engine
+ return engine in cls.COMPAT_ENGINES
+
+ def draw(self, context):
+
+ layout = self.layout
+
+ idblock = pov_context_tex_datablock(context)
+ # tex = context.pov_texture_slot
+ # mat = bpy.context.active_object.active_material
+ texslot = idblock.pov_texture_slots[
+ idblock.pov.active_texture_index
+ ] # bpy.data.textures[mat.active_texture_index]
+ # below tex is unused
+ tex = bpy.data.textures[idblock.pov_texture_slots[idblock.pov.active_texture_index].texture]
+
+ def factor_but(layout, toggle, factor, name):
+ row = layout.row(align=True)
+ row.prop(texslot, toggle, text="")
+ sub = row.row(align=True)
+ sub.active = getattr(texslot, toggle)
+ sub.prop(texslot, factor, text=name, slider=True)
+ return sub # XXX, temp. use_map_normal needs to override.
+
+ if isinstance(idblock, Material):
+ split = layout.split()
+
+ col = split.column()
+ if idblock.pov.type in {'SURFACE', 'WIRE'}:
+
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Diffuse:")
+ factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity")
+ factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
+ factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
+ factor_but(col, "use_map_translucency", "translucency_factor", "Translucency")
+
+ col.label(text="Specular:")
+ factor_but(col, "use_map_specular", "specular_factor", "Intensity")
+ factor_but(col, "use_map_color_spec", "specular_color_factor", "Color")
+ factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
+
+ col = split.column()
+ col.label(text="Shading:")
+ factor_but(col, "use_map_ambient", "ambient_factor", "Ambient")
+ factor_but(col, "use_map_emit", "emit_factor", "Emit")
+ factor_but(col, "use_map_mirror", "mirror_factor", "Mirror")
+ factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror")
+
+ col.label(text="Geometry:")
+ # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
+ sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal")
+ sub_tmp.active = texslot.use_map_normal or texslot.use_map_displacement
+ # END XXX
+
+ factor_but(col, "use_map_warp", "warp_factor", "Warp")
+ factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
+
+ elif idblock.pov.type == 'HALO':
+ layout.label(text="Halo:")
+
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
+ factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
+
+ col = split.column()
+ factor_but(col, "use_map_raymir", "raymir_factor", "Size")
+ factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
+ factor_but(col, "use_map_translucency", "translucency_factor", "Add")
+ elif idblock.pov.type == 'VOLUME':
+ layout.label(text="Volume:")
+
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_density", "density_factor", "Density")
+ factor_but(col, "use_map_emission", "emission_factor", "Emission")
+ factor_but(col, "use_map_scatter", "scattering_factor", "Scattering")
+ factor_but(col, "use_map_reflect", "reflection_factor", "Reflection")
+
+ col = split.column()
+ col.label(text=" ")
+ factor_but(col, "use_map_color_emission", "emission_color_factor", "Emission Color")
+ factor_but(
+ col,
+ "use_map_color_transmission",
+ "transmission_color_factor",
+ "Transmission Color",
+ )
+ factor_but(
+ col, "use_map_color_reflection", "reflection_color_factor", "Reflection Color"
+ )
+
+ layout.label(text="Geometry:")
+
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_warp", "warp_factor", "Warp")
+
+ col = split.column()
+ factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
+
+ elif isinstance(idblock, Light):
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_color", "color_factor", "Color")
+
+ col = split.column()
+ factor_but(col, "use_map_shadow", "shadow_factor", "Shadow")
+
+ elif isinstance(idblock, World):
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_blend", "blend_factor", "Blend")
+ factor_but(col, "use_map_horizon", "horizon_factor", "Horizon")
+
+ col = split.column()
+ factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
+ factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
+ elif isinstance(idblock, ParticleSettings):
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="General:")
+ factor_but(col, "use_map_time", "time_factor", "Time")
+ factor_but(col, "use_map_life", "life_factor", "Lifetime")
+ factor_but(col, "use_map_density", "density_factor", "Density")
+ factor_but(col, "use_map_size", "size_factor", "Size")
+
+ col = split.column()
+ col.label(text="Physics:")
+ factor_but(col, "use_map_velocity", "velocity_factor", "Velocity")
+ factor_but(col, "use_map_damp", "damp_factor", "Damp")
+ factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
+ factor_but(col, "use_map_field", "field_factor", "Force Fields")
+
+ layout.label(text="Hair:")
+
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_length", "length_factor", "Length")
+ factor_but(col, "use_map_clump", "clump_factor", "Clump")
+ factor_but(col, "use_map_twist", "twist_factor", "Twist")
+
+ col = split.column()
+ factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude")
+ factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency")
+ factor_but(col, "use_map_rough", "rough_factor", "Rough")
+
+ elif isinstance(idblock, FreestyleLineStyle):
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
+ col = split.column()
+ factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
+
+ layout.separator()
+
+ if not isinstance(idblock, ParticleSettings):
+ split = layout.split()
+
+ col = split.column()
+ # col.prop(tex, "blend_type", text="Blend") #deprecated since 2.8
+ # col.prop(tex, "use_rgb_to_intensity") #deprecated since 2.8
+ # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
+ # col.prop(tex, "color", text="") #deprecated since 2.8
+
+ col = split.column()
+ # col.prop(tex, "invert", text="Negative") #deprecated since 2.8
+ # col.prop(tex, "use_stencil") #deprecated since 2.8
+
+ # if isinstance(idblock, (Material, World)):
+ # col.prop(tex, "default_value", text="DVar", slider=True)
+
+
+class TEXTURE_PT_POV_tex_gamma(TextureButtonsPanel, Panel):
+ """Use this class to define pov texture gamma buttons."""
+
+ bl_label = "Image Gamma"
+ COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+ def draw_header(self, context):
+ tex = context.texture
+
+ self.layout.prop(tex.pov, "tex_gamma_enable", text="", icon='SEQ_LUMA_WAVEFORM')
+
+ def draw(self, context):
+ layout = self.layout
+
+ tex = context.texture
+
+ layout.active = tex.pov.tex_gamma_enable
+ layout.prop(tex.pov, "tex_gamma_value", text="Gamma Value")
+
+
+# commented out below UI for texture only custom code inside exported material:
+# class TEXTURE_PT_povray_replacement_text(TextureButtonsPanel, Panel):
+# bl_label = "Custom POV Code"
+# COMPAT_ENGINES = {'POVRAY_RENDER'}
+
+# def draw(self, context):
+# layout = self.layout
+
+# tex = context.texture
+
+# col = layout.column()
+# col.label(text="Replace properties with:")
+# col.prop(tex.pov, "replacement_text", text="")
+
+
+classes = (
+ WORLD_TEXTURE_SLOTS_UL_POV_layerlist,
+ TEXTURE_MT_POV_specials,
+ TEXTURE_PT_POV_context_texture,
+ TEXTURE_PT_colors,
+ TEXTURE_PT_POV_type,
+ TEXTURE_PT_POV_preview,
+ TEXTURE_PT_POV_parameters,
+ TEXTURE_PT_POV_tex_gamma,
+ MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist,
+ TEXTURE_OT_POV_texture_slot_add,
+ TEXTURE_OT_POV_texture_slot_remove,
+ TEXTURE_PT_POV_influence,
+ TEXTURE_PT_POV_mapping,
+)
+
+
+def register():
+
+ for cls in classes:
+ register_class(cls)
+
+
+def unregister():
+
+ for cls in reversed(classes):
+ if cls != TEXTURE_PT_context:
+ unregister_class(cls)
diff --git a/render_povray/texturing_properties.py b/render_povray/texturing_properties.py
new file mode 100755
index 00000000..bb89ee02
--- /dev/null
+++ b/render_povray/texturing_properties.py
@@ -0,0 +1,1137 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Declare texturing properties controllable in UI."""
+
+import bpy
+from bpy.utils import register_class, unregister_class
+from bpy.types import PropertyGroup
+from bpy.props import (
+ FloatVectorProperty,
+ StringProperty,
+ BoolProperty,
+ IntProperty,
+ FloatProperty,
+ EnumProperty,
+ PointerProperty,
+ CollectionProperty,
+)
+
+from .shading_properties import active_texture_name_from_uilist, active_texture_name_from_search
+
+###############################################################################
+# Texture slots (Material context) exported as POV texture properties.
+###############################################################################
+class MaterialTextureSlot(PropertyGroup):
+ """Declare material texture slot level properties for UI and translated to POV."""
+
+ bl_idname = ("pov_texture_slots",)
+ bl_description = ("Texture_slots from Blender-2.79",)
+
+ # Adding a "real" texture datablock as property is not possible
+ # (or at least not easy through a dynamically populated EnumProperty).
+ # That's why we'll use a prop_search() UILayout function in texturing_gui.py.
+ # So we'll assign the name of the needed texture datablock to the below StringProperty.
+ texture: StringProperty(update=active_texture_name_from_uilist)
+ # and use another temporary StringProperty to change the linked data
+ texture_search: StringProperty(
+ name="", update=active_texture_name_from_search, description="Browse Texture to be linked"
+ )
+
+ alpha_factor: FloatProperty(
+ name="Alpha", description="Amount texture affects alpha", default=1.0
+ )
+
+ ambient_factor: FloatProperty(
+ name="", description="Amount texture affects ambient", default=1.0
+ )
+
+ bump_method: EnumProperty(
+ name="",
+ description="Method to use for bump mapping",
+ items=(
+ ("BUMP_ORIGINAL", "Bump Original", ""),
+ ("BUMP_COMPATIBLE", "Bump Compatible", ""),
+ ("BUMP_DEFAULT", "Bump Default", ""),
+ ("BUMP_BEST_QUALITY", "Bump Best Quality", ""),
+ ),
+ default="BUMP_ORIGINAL",
+ )
+
+ bump_objectspace: EnumProperty(
+ name="",
+ description="Space to apply bump mapping in",
+ items=(
+ ("BUMP_VIEWSPACE", "Bump Viewspace", ""),
+ ("BUMP_OBJECTSPACE", "Bump Objectspace", ""),
+ ("BUMP_TEXTURESPACE", "Bump Texturespace", ""),
+ ),
+ default="BUMP_VIEWSPACE",
+ )
+
+ density_factor: FloatProperty(
+ name="", description="Amount texture affects density", default=1.0
+ )
+
+ diffuse_color_factor: FloatProperty(
+ name="", description="Amount texture affects diffuse color", default=1.0
+ )
+
+ diffuse_factor: FloatProperty(
+ name="", description="Amount texture affects diffuse reflectivity", default=1.0
+ )
+
+ displacement_factor: FloatProperty(
+ name="", description="Amount texture displaces the surface", default=0.2
+ )
+
+ emission_color_factor: FloatProperty(
+ name="", description="Amount texture affects emission color", default=1.0
+ )
+
+ emission_factor: FloatProperty(
+ name="", description="Amount texture affects emission", default=1.0
+ )
+
+ emit_factor: FloatProperty(name="", description="Amount texture affects emission", default=1.0)
+
+ hardness_factor: FloatProperty(
+ name="", description="Amount texture affects hardness", default=1.0
+ )
+
+ mapping: EnumProperty(
+ name="",
+ description="",
+ items=(
+ ("FLAT", "Flat", ""),
+ ("CUBE", "Cube", ""),
+ ("TUBE", "Tube", ""),
+ ("SPHERE", "Sphere", ""),
+ ),
+ default="FLAT",
+ )
+
+ mapping_x: EnumProperty(
+ name="",
+ description="",
+ items=(("NONE", "", ""), ("X", "", ""), ("Y", "", ""), ("Z", "", "")),
+ default="NONE",
+ )
+
+ mapping_y: EnumProperty(
+ name="",
+ description="",
+ items=(("NONE", "", ""), ("X", "", ""), ("Y", "", ""), ("Z", "", "")),
+ default="NONE",
+ )
+
+ mapping_z: EnumProperty(
+ name="",
+ description="",
+ items=(("NONE", "", ""), ("X", "", ""), ("Y", "", ""), ("Z", "", "")),
+ default="NONE",
+ )
+
+ mirror_factor: FloatProperty(
+ name="", description="Amount texture affects mirror color", default=1.0
+ )
+
+ normal_factor: FloatProperty(
+ name="", description="Amount texture affects normal values", default=1.0
+ )
+
+ normal_map_space: EnumProperty(
+ name="",
+ description="Sets space of normal map image",
+ items=(
+ ("CAMERA", "Camera", ""),
+ ("WORLD", "World", ""),
+ ("OBJECT", "Object", ""),
+ ("TANGENT", "Tangent", ""),
+ ),
+ default="CAMERA",
+ )
+
+ object: StringProperty(
+ name="Object",
+ description="Object to use for mapping with Object texture coordinates",
+ default="",
+ )
+
+ raymir_factor: FloatProperty(
+ name="", description="Amount texture affects ray mirror", default=1.0
+ )
+
+ reflection_color_factor: FloatProperty(
+ name="", description="Amount texture affects color of out-scattered light", default=1.0
+ )
+
+ reflection_factor: FloatProperty(
+ name="", description="Amount texture affects brightness of out-scattered light", default=1.0
+ )
+
+ scattering_factor: FloatProperty(
+ name="", description="Amount texture affects scattering", default=1.0
+ )
+
+ specular_color_factor: FloatProperty(
+ name="", description="Amount texture affects specular color", default=1.0
+ )
+
+ specular_factor: FloatProperty(
+ name="", description="Amount texture affects specular reflectivity", default=1.0
+ )
+
+ offset: FloatVectorProperty(
+ name="Offset",
+ description=("Fine tune of the texture mapping X, Y and Z locations "),
+ precision=4,
+ step=0.1,
+ soft_min=-100.0,
+ soft_max=100.0,
+ default=(0.0, 0.0, 0.0),
+ options={"ANIMATABLE"},
+ subtype="TRANSLATION",
+ )
+
+ scale: FloatVectorProperty(
+ name="Size",
+ subtype="XYZ",
+ size=3,
+ description="Set scaling for the texture’s X, Y and Z sizes ",
+ precision=4,
+ step=0.1,
+ soft_min=-100.0,
+ soft_max=100.0,
+ default=(1.0, 1.0, 1.0),
+ options={"ANIMATABLE"},
+ )
+
+ texture_coords: EnumProperty(
+ name="",
+ description="",
+ items=(
+ ("GLOBAL", "Global", ""),
+ ("OBJECT", "Object", ""),
+ ("UV", "UV", ""),
+ ("ORCO", "Original Coordinates", ""),
+ ("STRAND", "Strand", ""),
+ ("STICKY", "Sticky", ""),
+ ("WINDOW", "Window", ""),
+ ("NORMAL", "Normal", ""),
+ ("REFLECTION", "Reflection", ""),
+ ("STRESS", "Stress", ""),
+ ("TANGENT", "Tangent", ""),
+ ),
+ default="GLOBAL",
+ )
+
+ translucency_factor: FloatProperty(
+ name="", description="Amount texture affects translucency", default=1.0
+ )
+
+ transmission_color_factor: FloatProperty(
+ name="",
+ description="Amount texture affects result color after light has been scattered/absorbed",
+ default=1.0,
+ )
+
+ use: BoolProperty(name="", description="Enable this material texture slot", default=True)
+
+ use_from_dupli: BoolProperty(
+ name="",
+ description="Dupli’s instanced from verts, faces or particles, "
+ "inherit texture coordinate from their parent",
+ default=False,
+ )
+
+ use_from_original: BoolProperty(
+ name="",
+ description="Dupli’s derive their object coordinates from the "
+ "original objects transformation",
+ default=False,
+ )
+
+ use_interpolation: BoolProperty(
+ name="", description="Interpolates pixels using selected filter ", default=False
+ )
+
+ use_map_alpha: BoolProperty(
+ name="", description="Causes the texture to affect the alpha value", default=False
+ )
+
+ use_map_ambient: BoolProperty(
+ name="", description="Causes the texture to affect the value of ambient", default=False
+ )
+
+ use_map_color_diffuse: BoolProperty(
+ name="",
+ description="Causes the texture to affect basic color of the material",
+ default=True,
+ )
+
+ use_map_color_emission: BoolProperty(
+ name="", description="Causes the texture to affect the color of emission", default=False
+ )
+
+ use_map_color_reflection: BoolProperty(
+ name="",
+ description="Causes the texture to affect the color of scattered light",
+ default=False,
+ )
+
+ use_map_color_spec: BoolProperty(
+ name="", description="Causes the texture to affect the specularity color", default=False
+ )
+
+ use_map_color_transmission: BoolProperty(
+ name="",
+ description="Causes the texture to affect the result color after "
+ "other light has been scattered/absorbed",
+ default=False,
+ )
+
+ use_map_density: BoolProperty(
+ name="", description="Causes the texture to affect the volume’s density", default=False
+ )
+
+ use_map_diffuse: BoolProperty(
+ name="",
+ description="Causes the texture to affect the value of the materials diffuse reflectivity",
+ default=False,
+ )
+
+ use_map_displacement: BoolProperty(
+ name="", description="Let the texture displace the surface", default=False
+ )
+
+ use_map_emission: BoolProperty(
+ name="", description="Causes the texture to affect the volume’s emission", default=False
+ )
+
+ use_map_emit: BoolProperty(
+ name="", description="Causes the texture to affect the emit value", default=False
+ )
+
+ use_map_hardness: BoolProperty(
+ name="", description="Causes the texture to affect the hardness value", default=False
+ )
+
+ use_map_mirror: BoolProperty(
+ name="", description="Causes the texture to affect the mirror color", default=False
+ )
+
+ use_map_normal: BoolProperty(
+ name="", description="Causes the texture to affect the rendered normal", default=False
+ )
+
+ use_map_raymir: BoolProperty(
+ name="", description="Causes the texture to affect the ray-mirror value", default=False
+ )
+
+ use_map_reflect: BoolProperty(
+ name="",
+ description="Causes the texture to affect the reflected light’s brightness",
+ default=False,
+ )
+
+ use_map_scatter: BoolProperty(
+ name="", description="Causes the texture to affect the volume’s scattering", default=False
+ )
+
+ use_map_specular: BoolProperty(
+ name="",
+ description="Causes the texture to affect the value of specular reflectivity",
+ default=False,
+ )
+
+ use_map_translucency: BoolProperty(
+ name="", description="Causes the texture to affect the translucency value", default=False
+ )
+
+ use_map_warp: BoolProperty(
+ name="",
+ description="Let the texture warp texture coordinates of next channels",
+ default=False,
+ )
+
+ uv_layer: StringProperty(
+ name="", description="UV layer to use for mapping with UV texture coordinates", default=""
+ )
+
+ warp_factor: FloatProperty(
+ name="",
+ description="Amount texture affects texture coordinates of next channels",
+ default=0.0,
+ )
+
+ #######################################
+
+ blend_factor: FloatProperty(
+ name="Blend",
+ description="Amount texture affects color progression of the " "background",
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+ horizon_factor: FloatProperty(
+ name="Horizon",
+ description="Amount texture affects color of the horizon" "",
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+ object: StringProperty(
+ name="Object",
+ description="Object to use for mapping with Object texture coordinates",
+ default="",
+ )
+
+ texture_coords: EnumProperty(
+ name="Coordinates",
+ description="Texture coordinates used to map the texture onto the background",
+ items=(
+ ("VIEW", "View", "Use view vector for the texture coordinates"),
+ (
+ "GLOBAL",
+ "Global",
+ "Use global coordinates for the texture coordinates (interior mist)",
+ ),
+ (
+ "ANGMAP",
+ "AngMap",
+ "Use 360 degree angular coordinates, e.g. for spherical light probes",
+ ),
+ ("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
+ ("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
+ ("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
+ ("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates"),
+ ),
+ default="VIEW",
+ )
+
+ use_map_blend: BoolProperty(
+ name="Blend Map", description="Affect the color progression of the background", default=True
+ )
+
+ use_map_horizon: BoolProperty(
+ name="Horizon Map", description="Affect the color of the horizon", default=False
+ )
+
+ use_map_zenith_down: BoolProperty(
+ name="", description="Affect the color of the zenith below", default=False
+ )
+
+ use_map_zenith_up: BoolProperty(
+ name="Zenith Up Map", description="Affect the color of the zenith above", default=False
+ )
+
+ zenith_down_factor: FloatProperty(
+ name="Zenith Down",
+ description="Amount texture affects color of the zenith below",
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+ zenith_up_factor: FloatProperty(
+ name="Zenith Up",
+ description="Amount texture affects color of the zenith above",
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+
+###############################################################################
+# Texture slots (World context) exported as POV texture properties.
+###############################################################################
+class WorldTextureSlot(PropertyGroup):
+ """Declare world texture slot level properties for UI and translated to POV."""
+
+ bl_idname = ("pov_texture_slots",)
+ bl_description = ("Texture_slots from Blender-2.79",)
+
+ # Adding a "real" texture datablock as property is not possible
+ # (or at least not easy through a dynamically populated EnumProperty).
+ # That's why we'll use a prop_search() UILayout function in ui.py.
+ # So we'll assign the name of the needed texture datablock to the below StringProperty.
+ texture: StringProperty(update=active_texture_name_from_uilist)
+ # and use another temporary StringProperty to change the linked data
+ texture_search: StringProperty(
+ name="", update=active_texture_name_from_search, description="Browse Texture to be linked"
+ )
+
+ blend_factor: FloatProperty(
+ name="Blend",
+ description="Amount texture affects color progression of the " "background",
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+ horizon_factor: FloatProperty(
+ name="Horizon",
+ description="Amount texture affects color of the horizon",
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+ object: StringProperty(
+ name="Object",
+ description="Object to use for mapping with Object texture coordinates",
+ default="",
+ )
+
+ offset: FloatVectorProperty(
+ name="Offset",
+ description=("Fine tune of the texture mapping X, Y and Z locations "),
+ precision=4,
+ step=0.1,
+ soft_min=-100.0,
+ soft_max=100.0,
+ default=(0.0, 0.0, 0.0),
+ options={"ANIMATABLE"},
+ subtype="TRANSLATION",
+ )
+
+ scale: FloatVectorProperty(
+ name="Size",
+ subtype="XYZ",
+ size=3,
+ description="Set scaling for the texture’s X, Y and Z sizes ",
+ precision=4,
+ step=0.1,
+ soft_min=-100.0,
+ soft_max=100.0,
+ default=(1.0, 1.0, 1.0),
+ options={"ANIMATABLE"},
+ )
+
+ texture_coords: EnumProperty(
+ name="Coordinates",
+ description="Texture coordinates used to map the texture onto the background",
+ items=(
+ ("VIEW", "View", "Use view vector for the texture coordinates"),
+ (
+ "GLOBAL",
+ "Global",
+ "Use global coordinates for the texture coordinates (interior mist)",
+ ),
+ (
+ "ANGMAP",
+ "AngMap",
+ "Use 360 degree angular coordinates, e.g. for spherical light probes",
+ ),
+ ("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
+ ("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
+ ("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
+ ("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates"),
+ ),
+ default="VIEW",
+ )
+
+ use_map_blend: BoolProperty(
+ name="Blend Map", description="Affect the color progression of the background", default=True
+ )
+
+ use_map_horizon: BoolProperty(
+ name="Horizon Map", description="Affect the color of the horizon", default=False
+ )
+
+ use_map_zenith_down: BoolProperty(
+ name="", description="Affect the color of the zenith below", default=False
+ )
+
+ use_map_zenith_up: BoolProperty(
+ name="Zenith Up Map", description="Affect the color of the zenith above", default=False
+ )
+
+ zenith_down_factor: FloatProperty(
+ name="Zenith Down",
+ description="Amount texture affects color of the zenith below",
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+ zenith_up_factor: FloatProperty(
+ name="Zenith Up",
+ description="Amount texture affects color of the zenith above",
+ soft_min=0.0,
+ soft_max=1.0,
+ default=1.0,
+ )
+
+
+###############################################################################
+# Space properties from removed former Blender Internal
+###############################################################################
+
+# added below at superclass level so as to be available in World, Material,
+# and Light, for texture slots use
+
+bpy.types.ID.use_limited_texture_context = BoolProperty(
+ name="",
+ description="Use the limited version of texture user (for ‘old shading’ mode)",
+ default=True,
+)
+bpy.types.ID.texture_context = EnumProperty(
+ name="Texture context",
+ description="Type of texture data to display and edit",
+ items=(
+ ("MATERIAL", "", "Show material textures", "MATERIAL", 0), # "Show material textures"
+ ("WORLD", "", "Show world textures", "WORLD", 1), # "Show world textures"
+ ("LIGHT", "", "Show lamp textures", "LIGHT", 2), # "Show lamp textures"
+ ("PARTICLES", "", "Show particles textures", "PARTICLES", 3), # "Show particles textures"
+ ("LINESTYLE", "", "Show linestyle textures", "LINE_DATA", 4), # "Show linestyle textures"
+ ("OTHER", "", "Show other data textures", "TEXTURE_DATA", 5), # "Show other data textures"
+ ),
+ default="MATERIAL",
+)
+# bpy.types.ID.active_texture_index = IntProperty(
+# name = "Index for texture_slots",
+# default = 0,
+# )
+
+
+###############################################################################
+# Texture POV properties.
+###############################################################################
+
+
+class RenderPovSettingsTexture(PropertyGroup):
+ """Declare texture level properties controllable in UI and translated to POV."""
+
+ # former Space properties from removed Blender Internal
+ active_texture_index: IntProperty(name="Index for texture_slots", min=0, max=17, default=0)
+
+ use_limited_texture_context: BoolProperty(
+ name="",
+ description="Use the limited version of texture user (for ‘old shading’ mode)",
+ default=True,
+ )
+
+ texture_context: EnumProperty(
+ name="Texture context",
+ description="Type of texture data to display and edit",
+ items=(
+ ("MATERIAL", "", "Show material textures", "MATERIAL", 0), # "Show material textures"
+ ("WORLD", "", "Show world textures", "WORLD", 1), # "Show world textures"
+ ("LAMP", "", "Show lamp textures", "LIGHT", 2), # "Show lamp textures"
+ (
+ "PARTICLES",
+ "",
+ "Show particles textures",
+ "PARTICLES",
+ 3,
+ ), # "Show particles textures"
+ (
+ "LINESTYLE",
+ "",
+ "Show linestyle textures",
+ "LINE_DATA",
+ 4,
+ ), # "Show linestyle textures"
+ (
+ "OTHER",
+ "",
+ "Show other data textures",
+ "TEXTURE_DATA",
+ 5,
+ ), # "Show other data textures"
+ ),
+ default="MATERIAL",
+ )
+
+ # Custom texture gamma
+ tex_gamma_enable: BoolProperty(
+ name="Enable custom texture gamma",
+ description="Notify some custom gamma for which texture has been precorrected "
+ "without the file format carrying it and only if it differs from your "
+ "OS expected standard (see pov doc)",
+ default=False,
+ )
+
+ tex_gamma_value: FloatProperty(
+ name="Custom texture gamma",
+ description="value for which the file was issued e.g. a Raw photo is gamma 1.0",
+ min=0.45,
+ max=5.00,
+ soft_min=1.00,
+ soft_max=2.50,
+ default=1.00,
+ )
+
+ ##################################CustomPOV Code############################
+ # commented out below if we wanted custom pov code in texture only, inside exported material:
+ # replacement_text = StringProperty(
+ # name="Declared name:",
+ # description="Type the declared name in custom POV code or an external .inc "
+ # "it points at. pigment {} expected",
+ # default="")
+
+ tex_pattern_type: EnumProperty(
+ name="Texture_Type",
+ description="Choose between Blender or POV parameters to specify texture",
+ items=(
+ ("agate", "Agate", "", "PLUGIN", 0),
+ ("aoi", "Aoi", "", "PLUGIN", 1),
+ ("average", "Average", "", "PLUGIN", 2),
+ ("boxed", "Boxed", "", "PLUGIN", 3),
+ ("bozo", "Bozo", "", "PLUGIN", 4),
+ ("bumps", "Bumps", "", "PLUGIN", 5),
+ ("cells", "Cells", "", "PLUGIN", 6),
+ ("crackle", "Crackle", "", "PLUGIN", 7),
+ ("cubic", "Cubic", "", "PLUGIN", 8),
+ ("cylindrical", "Cylindrical", "", "PLUGIN", 9),
+ ("density_file", "Density", "(.df3)", "PLUGIN", 10),
+ ("dents", "Dents", "", "PLUGIN", 11),
+ ("fractal", "Fractal", "", "PLUGIN", 12),
+ ("function", "Function", "", "PLUGIN", 13),
+ ("gradient", "Gradient", "", "PLUGIN", 14),
+ ("granite", "Granite", "", "PLUGIN", 15),
+ ("image_pattern", "Image pattern", "", "PLUGIN", 16),
+ ("leopard", "Leopard", "", "PLUGIN", 17),
+ ("marble", "Marble", "", "PLUGIN", 18),
+ ("onion", "Onion", "", "PLUGIN", 19),
+ ("pigment_pattern", "pigment pattern", "", "PLUGIN", 20),
+ ("planar", "Planar", "", "PLUGIN", 21),
+ ("quilted", "Quilted", "", "PLUGIN", 22),
+ ("radial", "Radial", "", "PLUGIN", 23),
+ ("ripples", "Ripples", "", "PLUGIN", 24),
+ ("slope", "Slope", "", "PLUGIN", 25),
+ ("spherical", "Spherical", "", "PLUGIN", 26),
+ ("spiral1", "Spiral1", "", "PLUGIN", 27),
+ ("spiral2", "Spiral2", "", "PLUGIN", 28),
+ ("spotted", "Spotted", "", "PLUGIN", 29),
+ ("waves", "Waves", "", "PLUGIN", 30),
+ ("wood", "Wood", "", "PLUGIN", 31),
+ ("wrinkles", "Wrinkles", "", "PLUGIN", 32),
+ ("brick", "Brick", "", "PLUGIN", 33),
+ ("checker", "Checker", "", "PLUGIN", 34),
+ ("hexagon", "Hexagon", "", "PLUGIN", 35),
+ ("object", "Mesh", "", "PLUGIN", 36),
+ ("emulator", "Blender Type Emulator", "", "SCRIPTPLUGINS", 37),
+ ),
+ default="emulator",
+ )
+
+ magnet_style: EnumProperty(
+ name="Magnet style",
+ description="magnet or julia",
+ items=(("mandel", "Mandelbrot", ""), ("julia", "Julia", "")),
+ default="julia",
+ )
+
+ magnet_type: IntProperty(name="Magnet_type", description="1 or 2", min=1, max=2, default=2)
+
+ warp_types: EnumProperty(
+ name="Warp Types",
+ description="Select the type of warp",
+ items=(
+ ("PLANAR", "Planar", ""),
+ ("CUBIC", "Cubic", ""),
+ ("SPHERICAL", "Spherical", ""),
+ ("TOROIDAL", "Toroidal", ""),
+ ("CYLINDRICAL", "Cylindrical", ""),
+ ("NONE", "None", "No indentation"),
+ ),
+ default="NONE",
+ )
+
+ warp_orientation: EnumProperty(
+ name="Warp Orientation",
+ description="Select the orientation of warp",
+ items=(("x", "X", ""), ("y", "Y", ""), ("z", "Z", "")),
+ default="y",
+ )
+
+ wave_type: EnumProperty(
+ name="Waves type",
+ description="Select the type of waves",
+ items=(
+ ("ramp", "Ramp", ""),
+ ("sine", "Sine", ""),
+ ("scallop", "Scallop", ""),
+ ("cubic", "Cubic", ""),
+ ("poly", "Poly", ""),
+ ("triangle", "Triangle", ""),
+ ),
+ default="ramp",
+ )
+
+ gen_noise: IntProperty(
+ name="Noise Generators", description="Noise Generators", min=1, max=3, default=1
+ )
+
+ warp_dist_exp: FloatProperty(
+ name="Distance exponent", description="Distance exponent", min=0.0, max=100.0, default=1.0
+ )
+
+ warp_tor_major_radius: FloatProperty(
+ name="Major radius",
+ description="Torus is distance from major radius",
+ min=0.0,
+ max=5.0,
+ default=1.0,
+ )
+
+ warp_turbulence_x: FloatProperty(
+ name="Turbulence X", description="Turbulence X", min=0.0, max=5.0, default=0.0
+ )
+
+ warp_turbulence_y: FloatProperty(
+ name="Turbulence Y", description="Turbulence Y", min=0.0, max=5.0, default=0.0
+ )
+
+ warp_turbulence_z: FloatProperty(
+ name="Turbulence Z", description="Turbulence Z", min=0.0, max=5.0, default=0.0
+ )
+
+ modifier_octaves: IntProperty(
+ name="Turbulence octaves", description="Turbulence octaves", min=1, max=10, default=1
+ )
+
+ modifier_lambda: FloatProperty(
+ name="Turbulence lambda", description="Turbulence lambda", min=0.0, max=5.0, default=1.00
+ )
+
+ modifier_omega: FloatProperty(
+ name="Turbulence omega", description="Turbulence omega", min=0.0, max=10.0, default=1.00
+ )
+
+ modifier_phase: FloatProperty(
+ name="Phase",
+ description="The phase value causes the map entries to be shifted so that the map "
+ "starts and ends at a different place",
+ min=0.0,
+ max=2.0,
+ default=0.0,
+ )
+
+ modifier_frequency: FloatProperty(
+ name="Frequency",
+ description="The frequency keyword adjusts the number of times that a color map "
+ "repeats over one cycle of a pattern",
+ min=0.0,
+ max=25.0,
+ default=2.0,
+ )
+
+ modifier_turbulence: FloatProperty(
+ name="Turbulence", description="Turbulence", min=0.0, max=5.0, default=2.0
+ )
+
+ modifier_numbers: IntProperty(name="Numbers", description="Numbers", min=1, max=27, default=2)
+
+ modifier_control0: IntProperty(
+ name="Control0", description="Control0", min=0, max=100, default=1
+ )
+
+ modifier_control1: IntProperty(
+ name="Control1", description="Control1", min=0, max=100, default=1
+ )
+
+ brick_size_x: FloatProperty(
+ name="Brick size x", description="", min=0.0000, max=1.0000, default=0.2500
+ )
+
+ brick_size_y: FloatProperty(
+ name="Brick size y", description="", min=0.0000, max=1.0000, default=0.0525
+ )
+
+ brick_size_z: FloatProperty(
+ name="Brick size z", description="", min=0.0000, max=1.0000, default=0.1250
+ )
+
+ brick_mortar: FloatProperty(
+ name="Mortar", description="Mortar", min=0.000, max=1.500, default=0.01
+ )
+
+ julia_complex_1: FloatProperty(
+ name="Julia Complex 1", description="", min=0.000, max=1.500, default=0.360
+ )
+
+ julia_complex_2: FloatProperty(
+ name="Julia Complex 2", description="", min=0.000, max=1.500, default=0.250
+ )
+
+ f_iter: IntProperty(name="Fractal Iteration", description="", min=0, max=100, default=20)
+
+ f_exponent: IntProperty(name="Fractal Exponent", description="", min=2, max=33, default=2)
+
+ f_ior: IntProperty(name="Fractal Interior", description="", min=1, max=6, default=1)
+
+ f_ior_fac: FloatProperty(
+ name="Fractal Interior Factor", description="", min=0.0, max=10.0, default=1.0
+ )
+
+ f_eor: IntProperty(name="Fractal Exterior", description="", min=1, max=8, default=1)
+
+ f_eor_fac: FloatProperty(
+ name="Fractal Exterior Factor", description="", min=0.0, max=10.0, default=1.0
+ )
+
+ grad_orient_x: IntProperty(
+ name="Gradient orientation X", description="", min=0, max=1, default=0
+ )
+
+ grad_orient_y: IntProperty(
+ name="Gradient orientation Y", description="", min=0, max=1, default=1
+ )
+
+ grad_orient_z: IntProperty(
+ name="Gradient orientation Z", description="", min=0, max=1, default=0
+ )
+
+ pave_sides: EnumProperty(
+ name="Pavement sides",
+ description="",
+ items=(("3", "3", ""), ("4", "4", ""), ("6", "6", "")),
+ default="3",
+ )
+
+ pave_pat_2: IntProperty(
+ name="Pavement pattern 2", description="maximum: 2", min=1, max=2, default=2
+ )
+
+ pave_pat_3: IntProperty(
+ name="Pavement pattern 3", description="maximum: 3", min=1, max=3, default=3
+ )
+
+ pave_pat_4: IntProperty(
+ name="Pavement pattern 4", description="maximum: 4", min=1, max=4, default=4
+ )
+
+ pave_pat_5: IntProperty(
+ name="Pavement pattern 5", description="maximum: 5", min=1, max=5, default=5
+ )
+
+ pave_pat_7: IntProperty(
+ name="Pavement pattern 7", description="maximum: 7", min=1, max=7, default=7
+ )
+
+ pave_pat_12: IntProperty(
+ name="Pavement pattern 12", description="maximum: 12", min=1, max=12, default=12
+ )
+
+ pave_pat_22: IntProperty(
+ name="Pavement pattern 22", description="maximum: 22", min=1, max=22, default=22
+ )
+
+ pave_pat_35: IntProperty(
+ name="Pavement pattern 35", description="maximum: 35", min=1, max=35, default=35
+ )
+
+ pave_tiles: IntProperty(
+ name="Pavement tiles",
+ description="If sides = 6, maximum tiles 5!!!",
+ min=1,
+ max=6,
+ default=1,
+ )
+
+ pave_form: IntProperty(name="Pavement form", description="", min=0, max=4, default=0)
+
+ #########FUNCTIONS#############################################################################
+ #########FUNCTIONS#############################################################################
+
+ func_list: EnumProperty(
+ name="Functions",
+ description="Select the function for create pattern",
+ items=(
+ ("NONE", "None", "No indentation"),
+ ("f_algbr_cyl1", "Algbr cyl1", ""),
+ ("f_algbr_cyl2", "Algbr cyl2", ""),
+ ("f_algbr_cyl3", "Algbr cyl3", ""),
+ ("f_algbr_cyl4", "Algbr cyl4", ""),
+ ("f_bicorn", "Bicorn", ""),
+ ("f_bifolia", "Bifolia", ""),
+ ("f_blob", "Blob", ""),
+ ("f_blob2", "Blob2", ""),
+ ("f_boy_surface", "Boy surface", ""),
+ ("f_comma", "Comma", ""),
+ ("f_cross_ellipsoids", "Cross ellipsoids", ""),
+ ("f_crossed_trough", "Crossed trough", ""),
+ ("f_cubic_saddle", "Cubic saddle", ""),
+ ("f_cushion", "Cushion", ""),
+ ("f_devils_curve", "Devils curve", ""),
+ ("f_devils_curve_2d", "Devils curve 2d", ""),
+ ("f_dupin_cyclid", "Dupin cyclid", ""),
+ ("f_ellipsoid", "Ellipsoid", ""),
+ ("f_enneper", "Enneper", ""),
+ ("f_flange_cover", "Flange cover", ""),
+ ("f_folium_surface", "Folium surface", ""),
+ ("f_folium_surface_2d", "Folium surface 2d", ""),
+ ("f_glob", "Glob", ""),
+ ("f_heart", "Heart", ""),
+ ("f_helical_torus", "Helical torus", ""),
+ ("f_helix1", "Helix1", ""),
+ ("f_helix2", "Helix2", ""),
+ ("f_hex_x", "Hex x", ""),
+ ("f_hex_y", "Hex y", ""),
+ ("f_hetero_mf", "Hetero mf", ""),
+ ("f_hunt_surface", "Hunt surface", ""),
+ ("f_hyperbolic_torus", "Hyperbolic torus", ""),
+ ("f_isect_ellipsoids", "Isect ellipsoids", ""),
+ ("f_kampyle_of_eudoxus", "Kampyle of eudoxus", ""),
+ ("f_kampyle_of_eudoxus_2d", "Kampyle of eudoxus 2d", ""),
+ ("f_klein_bottle", "Klein bottle", ""),
+ ("f_kummer_surface_v1", "Kummer surface v1", ""),
+ ("f_kummer_surface_v2", "Kummer surface v2", ""),
+ ("f_lemniscate_of_gerono", "Lemniscate of gerono", ""),
+ ("f_lemniscate_of_gerono_2d", "Lemniscate of gerono 2d", ""),
+ ("f_mesh1", "Mesh1", ""),
+ ("f_mitre", "Mitre", ""),
+ ("f_nodal_cubic", "Nodal cubic", ""),
+ ("f_noise3d", "Noise3d", ""),
+ ("f_noise_generator", "Noise generator", ""),
+ ("f_odd", "Odd", ""),
+ ("f_ovals_of_cassini", "Ovals of cassini", ""),
+ ("f_paraboloid", "Paraboloid", ""),
+ ("f_parabolic_torus", "Parabolic torus", ""),
+ ("f_ph", "Ph", ""),
+ ("f_pillow", "Pillow", ""),
+ ("f_piriform", "Piriform", ""),
+ ("f_piriform_2d", "Piriform 2d", ""),
+ ("f_poly4", "Poly4", ""),
+ ("f_polytubes", "Polytubes", ""),
+ ("f_quantum", "Quantum", ""),
+ ("f_quartic_paraboloid", "Quartic paraboloid", ""),
+ ("f_quartic_saddle", "Quartic saddle", ""),
+ ("f_quartic_cylinder", "Quartic cylinder", ""),
+ ("f_r", "R", ""),
+ ("f_ridge", "Ridge", ""),
+ ("f_ridged_mf", "Ridged mf", ""),
+ ("f_rounded_box", "Rounded box", ""),
+ ("f_sphere", "Sphere", ""),
+ ("f_spikes", "Spikes", ""),
+ ("f_spikes_2d", "Spikes 2d", ""),
+ ("f_spiral", "Spiral", ""),
+ ("f_steiners_roman", "Steiners roman", ""),
+ ("f_strophoid", "Strophoid", ""),
+ ("f_strophoid_2d", "Strophoid 2d", ""),
+ ("f_superellipsoid", "Superellipsoid", ""),
+ ("f_th", "Th", ""),
+ ("f_torus", "Torus", ""),
+ ("f_torus2", "Torus2", ""),
+ ("f_torus_gumdrop", "Torus gumdrop", ""),
+ ("f_umbrella", "Umbrella", ""),
+ ("f_witch_of_agnesi", "Witch of agnesi", ""),
+ ("f_witch_of_agnesi_2d", "Witch of agnesi 2d", ""),
+ ),
+ default="NONE",
+ )
+
+ func_x: FloatProperty(name="FX", description="", min=0.0, max=25.0, default=1.0)
+
+ func_plus_x: EnumProperty(
+ name="Func plus x",
+ description="",
+ items=(("NONE", "None", ""), ("increase", "*", ""), ("plus", "+", "")),
+ default="NONE",
+ )
+
+ func_y: FloatProperty(name="FY", description="", min=0.0, max=25.0, default=1.0)
+
+ func_plus_y: EnumProperty(
+ name="Func plus y",
+ description="",
+ items=(("NONE", "None", ""), ("increase", "*", ""), ("plus", "+", "")),
+ default="NONE",
+ )
+
+ func_z: FloatProperty(name="FZ", description="", min=0.0, max=25.0, default=1.0)
+
+ func_plus_z: EnumProperty(
+ name="Func plus z",
+ description="",
+ items=(("NONE", "None", ""), ("increase", "*", ""), ("plus", "+", "")),
+ default="NONE",
+ )
+
+ func_P0: FloatProperty(name="P0", description="", min=0.0, max=25.0, default=1.0)
+
+ func_P1: FloatProperty(name="P1", description="", min=0.0, max=25.0, default=1.0)
+
+ func_P2: FloatProperty(name="P2", description="", min=0.0, max=25.0, default=1.0)
+
+ func_P3: FloatProperty(name="P3", description="", min=0.0, max=25.0, default=1.0)
+
+ func_P4: FloatProperty(name="P4", description="", min=0.0, max=25.0, default=1.0)
+
+ func_P5: FloatProperty(name="P5", description="", min=0.0, max=25.0, default=1.0)
+
+ func_P6: FloatProperty(name="P6", description="", min=0.0, max=25.0, default=1.0)
+
+ func_P7: FloatProperty(name="P7", description="", min=0.0, max=25.0, default=1.0)
+
+ func_P8: FloatProperty(name="P8", description="", min=0.0, max=25.0, default=1.0)
+
+ func_P9: FloatProperty(name="P9", description="", min=0.0, max=25.0, default=1.0)
+
+ #########################################
+ tex_rot_x: FloatProperty(name="Rotate X", description="", min=-180.0, max=180.0, default=0.0)
+
+ tex_rot_y: FloatProperty(name="Rotate Y", description="", min=-180.0, max=180.0, default=0.0)
+
+ tex_rot_z: FloatProperty(name="Rotate Z", description="", min=-180.0, max=180.0, default=0.0)
+
+ tex_mov_x: FloatProperty(
+ name="Move X", description="", min=-100000.0, max=100000.0, default=0.0
+ )
+
+ tex_mov_y: FloatProperty(
+ name="Move Y", description="", min=-100000.0, max=100000.0, default=0.0
+ )
+
+ tex_mov_z: FloatProperty(
+ name="Move Z", description="", min=-100000.0, max=100000.0, default=0.0
+ )
+
+ tex_scale_x: FloatProperty(name="Scale X", description="", min=0.0, max=10000.0, default=1.0)
+
+ tex_scale_y: FloatProperty(name="Scale Y", description="", min=0.0, max=10000.0, default=1.0)
+
+ tex_scale_z: FloatProperty(name="Scale Z", description="", min=0.0, max=10000.0, default=1.0)
+
+
+classes = (MaterialTextureSlot, WorldTextureSlot, RenderPovSettingsTexture)
+
+
+def register():
+ for cls in classes:
+ register_class(cls)
+
+ bpy.types.Material.pov_texture_slots = CollectionProperty(type=MaterialTextureSlot)
+ bpy.types.World.pov_texture_slots = CollectionProperty(type=WorldTextureSlot)
+ bpy.types.Texture.pov = PointerProperty(type=RenderPovSettingsTexture)
+
+
+def unregister():
+ del bpy.types.Texture.pov
+ del bpy.types.World.pov_texture_slots
+ del bpy.types.Material.pov_texture_slots
+
+ for cls in reversed(classes):
+ unregister_class(cls)
diff --git a/render_povray/ui.py b/render_povray/ui.py
deleted file mode 100644
index 297c2e0d..00000000
--- a/render_povray/ui.py
+++ /dev/null
@@ -1,4719 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-"""User interface for the POV tools"""
-
-import bpy
-import sys # really import here and in render.py?
-import os # really import here and in render.py?
-import addon_utils
-from time import sleep
-from os.path import isfile
-from bpy.app.handlers import persistent
-from bl_operators.presets import AddPresetBase
-from bpy.utils import register_class, unregister_class
-from bpy.types import (
- Operator,
- Menu,
- UIList,
- Panel,
- Brush,
- Material,
- Light,
- World,
- ParticleSettings,
- FreestyleLineStyle,
-)
-
-# Example of wrapping every class 'as is'
-from bl_ui import properties_output
-
-for member in dir(properties_output):
- subclass = getattr(properties_output, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_output
-
-from bl_ui import properties_freestyle
-for member in dir(properties_freestyle):
- subclass = getattr(properties_freestyle, member)
- try:
- if not (subclass.bl_space_type == 'PROPERTIES'
- and subclass.bl_context == "render"):
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- #subclass.bl_parent_id = "RENDER_PT_POV_filter"
- except:
- pass
-del properties_freestyle
-
-from bl_ui import properties_view_layer
-
-for member in dir(properties_view_layer):
- subclass = getattr(properties_view_layer, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_view_layer
-
-# Use some of the existing buttons.
-from bl_ui import properties_render
-
-# DEPRECATED#properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
-# DEPRECATED#properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER')
-# properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
-# TORECREATE##DEPRECATED#properties_render.RENDER_PT_shading.COMPAT_ENGINES.add('POVRAY_RENDER')
-# DEPRECATED#properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
-del properties_render
-
-
-# Use only a subset of the world panels
-from bl_ui import properties_world
-
-# TORECREATE##DEPRECATED#properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER')
-properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER')
-# TORECREATE##DEPRECATED#properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER')
-# TORECREATE##DEPRECATED#properties_world.WORLD_PT_mist.COMPAT_ENGINES.add('POVRAY_RENDER')
-del properties_world
-
-
-# Example of wrapping every class 'as is'
-from bl_ui import properties_texture
-from bl_ui.properties_texture import context_tex_datablock
-from bl_ui.properties_texture import texture_filter_common
-
-for member in dir(properties_texture):
- subclass = getattr(properties_texture, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_texture
-
-# Physics Main wrapping every class 'as is'
-from bl_ui import properties_physics_common
-
-for member in dir(properties_physics_common):
- subclass = getattr(properties_physics_common, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_physics_common
-
-# Physics Rigid Bodies wrapping every class 'as is'
-from bl_ui import properties_physics_rigidbody
-
-for member in dir(properties_physics_rigidbody):
- subclass = getattr(properties_physics_rigidbody, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_physics_rigidbody
-
-# Physics Rigid Body Constraint wrapping every class 'as is'
-from bl_ui import properties_physics_rigidbody_constraint
-
-for member in dir(properties_physics_rigidbody_constraint):
- subclass = getattr(properties_physics_rigidbody_constraint, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_physics_rigidbody_constraint
-
-# Physics Smoke wrapping every class 'as is'
-from bl_ui import properties_physics_fluid
-
-for member in dir(properties_physics_fluid):
- subclass = getattr(properties_physics_fluid, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_physics_fluid
-
-# Physics softbody wrapping every class 'as is'
-from bl_ui import properties_physics_softbody
-
-for member in dir(properties_physics_softbody):
- subclass = getattr(properties_physics_softbody, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_physics_softbody
-
-# Physics Fluid wrapping every class 'as is'
-from bl_ui import properties_physics_fluid
-
-for member in dir(properties_physics_fluid):
- subclass = getattr(properties_physics_fluid, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_physics_fluid
-
-# Physics Field wrapping every class 'as is'
-from bl_ui import properties_physics_field
-
-for member in dir(properties_physics_field):
- subclass = getattr(properties_physics_field, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_physics_field
-
-# Physics Cloth wrapping every class 'as is'
-from bl_ui import properties_physics_cloth
-
-for member in dir(properties_physics_cloth):
- subclass = getattr(properties_physics_cloth, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_physics_cloth
-
-# Physics Dynamic Paint wrapping every class 'as is'
-from bl_ui import properties_physics_dynamicpaint
-
-for member in dir(properties_physics_dynamicpaint):
- subclass = getattr(properties_physics_dynamicpaint, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_physics_dynamicpaint
-
-
-# Example of wrapping every class 'as is'
-from bl_ui import properties_data_modifier
-
-for member in dir(properties_data_modifier):
- subclass = getattr(properties_data_modifier, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_data_modifier
-
-# Example of wrapping every class 'as is' except some
-from bl_ui import properties_material
-
-for member in dir(properties_material):
- subclass = getattr(properties_material, member)
- try:
- # mat=bpy.context.active_object.active_material
- # if (mat and mat.pov.type == "SURFACE"
- # and not (mat.pov.material_use_nodes or mat.use_nodes)):
- # and (engine in cls.COMPAT_ENGINES)) if subclasses were sorted
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_material
-
-
-from bl_ui import properties_data_camera
-
-for member in dir(properties_data_camera):
- subclass = getattr(properties_data_camera, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_data_camera
-
-
-from bl_ui import properties_particle as properties_particle
-
-for member in dir(
- properties_particle
-): # add all "particle" panels from blender
- subclass = getattr(properties_particle, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- except:
- pass
-del properties_particle
-
-
-############# POV-Centric WORSPACE #############
-@persistent
-def povCentricWorkspace(dummy):
- """Set up a POV centric Workspace if addon was activated and saved as default renderer
-
- This would bring a ’_RestrictData’ error because UI needs to be fully loaded before
- workspace changes so registering this function in bpy.app.handlers is needed.
- By default handlers are freed when loading new files, but here we want the handler
- to stay running across multiple files as part of this add-on. That is why the the
- bpy.app.handlers.persistent decorator is used (@persistent) above.
- """
-
- wsp = bpy.data.workspaces.get('Scripting')
- context = bpy.context
- if wsp is not None and context.scene.render.engine == 'POVRAY_RENDER':
- new_wsp = bpy.ops.workspace.duplicate({'workspace': wsp})
- bpy.data.workspaces['Scripting.001'].name='POV'
- # Already done it would seem, but explicitly make this workspaces the active one
- context.window.workspace = bpy.data.workspaces['POV']
- pov_screen = bpy.data.workspaces['POV'].screens[0]
- pov_workspace = pov_screen.areas
-
-
- override = bpy.context.copy()
-
- for area in pov_workspace:
- if area.type == 'VIEW_3D':
- for region in [r for r in area.regions if r.type == 'WINDOW']:
- for space in area.spaces:
- if space.type == 'VIEW_3D':
- #override['screen'] = pov_screen
- override['area'] = area
- override['region']= region
- #bpy.data.workspaces['POV'].screens[0].areas[6].spaces[0].width = 333 # Read only, how do we set ?
- #This has a glitch:
- #bpy.ops.screen.area_move(override, x=(area.x + area.width), y=(area.y + 5), delta=100)
- #bpy.ops.screen.area_move(override, x=(area.x + 5), y=area.y, delta=-100)
-
- bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'TEXT_EDITOR')
- space.show_region_ui = True
- #bpy.ops.screen.region_scale(override)
- #bpy.ops.screen.region_scale()
- break
-
- elif area.type == 'CONSOLE':
- for region in [r for r in area.regions if r.type == 'WINDOW']:
- for space in area.spaces:
- if space.type == 'CONSOLE':
- #override['screen'] = pov_screen
- override['area'] = area
- override['region']= region
- bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'INFO')
-
- break
- elif area.type == 'INFO':
- for region in [r for r in area.regions if r.type == 'WINDOW']:
- for space in area.spaces:
- if space.type == 'INFO':
- #override['screen'] = pov_screen
- override['area'] = area
- override['region']= region
- bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'CONSOLE')
-
- break
-
- elif area.type == 'TEXT_EDITOR':
- for region in [r for r in area.regions if r.type == 'WINDOW']:
- for space in area.spaces:
- if space.type == 'TEXT_EDITOR':
- #override['screen'] = pov_screen
- override['area'] = area
- override['region']= region
- #bpy.ops.screen.space_type_set_or_cycle(space_type='VIEW_3D')
- #space.type = 'VIEW_3D'
- bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'VIEW_3D')
-
- #bpy.ops.screen.area_join(override, cursor=(area.x, area.y + area.height))
-
- break
-
-
- if area.type == 'VIEW_3D':
- for region in [r for r in area.regions if r.type == 'WINDOW']:
- for space in area.spaces:
- if space.type == 'VIEW_3D':
- #override['screen'] = pov_screen
- override['area'] = area
- override['region']= region
- bpy.ops.screen.region_quadview(override)
- space.region_3d.view_perspective = 'CAMERA'
- #bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'TEXT_EDITOR')
- #bpy.ops.screen.region_quadview(override)
-
-
-
-
-
-
- bpy.data.workspaces.update()
- # Already outliners but invert both types
- pov_workspace[1].spaces[0].display_mode = 'LIBRARIES'
- pov_workspace[3].spaces[0].display_mode = 'VIEW_LAYER'
-
- '''
- for window in bpy.context.window_manager.windows:
- for area in [a for a in window.screen.areas if a.type == 'VIEW_3D']:
- for region in [r for r in area.regions if r.type == 'WINDOW']:
- context_override = {
- 'window': window,
- 'screen': window.screen,
- 'area': area,
- 'region': region,
- 'space_data': area.spaces.active,
- 'scene': bpy.context.scene
- }
- bpy.ops.view3d.camera_to_view(context_override)
- '''
-
-
- else:
- print("default 'Scripting' workspace needed for POV centric Workspace")
-
-
-
-
-
-
-
-class WORLD_MT_POV_presets(Menu):
- bl_label = "World Presets"
- preset_subdir = "pov/world"
- preset_operator = "script.execute_preset"
- draw = bpy.types.Menu.draw_preset
-
-
-class WORLD_OT_POV_add_preset(AddPresetBase, Operator):
- """Add a World Preset"""
-
- bl_idname = "object.world_preset_add"
- bl_label = "Add World Preset"
- preset_menu = "WORLD_MT_POV_presets"
-
- # variable used for all preset values
- preset_defines = ["scene = bpy.context.scene"]
-
- # properties to store in the preset
- preset_values = [
- "scene.world.use_sky_blend",
- "scene.world.horizon_color",
- "scene.world.zenith_color",
- "scene.world.ambient_color",
- "scene.world.mist_settings.use_mist",
- "scene.world.mist_settings.intensity",
- "scene.world.mist_settings.depth",
- "scene.world.mist_settings.start",
- "scene.pov.media_enable",
- "scene.pov.media_scattering_type",
- "scene.pov.media_samples",
- "scene.pov.media_diffusion_scale",
- "scene.pov.media_diffusion_color",
- "scene.pov.media_absorption_scale",
- "scene.pov.media_absorption_color",
- "scene.pov.media_eccentricity",
- ]
-
- # where to store the preset
- preset_subdir = "pov/world"
-
-
-def check_material(mat):
- if mat is not None:
- if mat.use_nodes:
- if (
- not mat.node_tree
- ): # FORMERLY : #mat.active_node_material is not None:
- return True
- return False
- return True
- return False
-
-
-def simple_material(mat):
- """Test if a material uses nodes"""
- if (mat is not None) and (not mat.use_nodes):
- return True
- return False
-
-
-def check_add_mesh_extra_objects():
- """Test if Add mesh extra objects addon is activated
-
- This addon is currently used to generate the proxy for POV parametric
- surface which is almost the same priciple as its Math xyz surface
- """
- if "add_mesh_extra_objects" in bpy.context.preferences.addons.keys():
- return True
- return False
-
-def check_render_freestyle_svg():
- """Test if Freestyle SVG Exporter addon is activated
-
- This addon is currently used to generate the SVG lines file
- when Freestyle is enabled alongside POV
- """
- if "render_freestyle_svg" in bpy.context.preferences.addons.keys():
- return True
- return False
-
-def locate_docpath():
- """POV can be installed with some include files.
-
- Get their path as defined in user preferences or registry keys for
- the user to be able to invoke them."""
-
- addon_prefs = bpy.context.preferences.addons[__package__].preferences
- # Use the system preference if its set.
- pov_documents = addon_prefs.docpath_povray
- if pov_documents:
- if os.path.exists(pov_documents):
- return pov_documents
- else:
- print(
- "User Preferences path to povray documents %r NOT FOUND, checking $PATH"
- % pov_documents
- )
-
- # Windows Only
- if sys.platform[:3] == "win":
- import winreg
-
- try:
- win_reg_key = winreg.OpenKey(
- winreg.HKEY_CURRENT_USER, "Software\\POV-Ray\\v3.7\\Windows"
- )
- win_docpath = winreg.QueryValueEx(win_reg_key, "DocPath")[0]
- pov_documents = os.path.join(win_docpath, "Insert Menu")
- if os.path.exists(pov_documents):
- return pov_documents
- except FileNotFoundError:
- return ""
- # search the path all os's
- pov_documents_default = "include"
-
- os_path_ls = os.getenv("PATH").split(':') + [""]
-
- for dir_name in os_path_ls:
- pov_documents = os.path.join(dir_name, pov_documents_default)
- if os.path.exists(pov_documents):
- return pov_documents
- return ""
-
-
-def pov_context_tex_datablock(context):
- """Texture context type recreated as deprecated in blender 2.8"""
-
- idblock = context.brush
- if idblock and context.scene.texture_context == 'OTHER':
- return idblock
-
- # idblock = bpy.context.active_object.active_material
- idblock = context.view_layer.objects.active.active_material
- if idblock and context.scene.texture_context == 'MATERIAL':
- return idblock
-
- idblock = context.scene.world
- if idblock and context.scene.texture_context == 'WORLD':
- return idblock
-
- idblock = context.light
- if idblock and context.scene.texture_context == 'LIGHT':
- return idblock
-
- if context.particle_system and context.scene.texture_context == 'PARTICLES':
- idblock = context.particle_system.settings
-
- return idblock
-
- idblock = context.line_style
- if idblock and context.scene.texture_context == 'LINESTYLE':
- return idblock
-
-
-class RenderButtonsPanel:
- """Use this class to define buttons from the render tab of
- properties window."""
-
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "render"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
- @classmethod
- def poll(cls, context):
- rd = context.scene.render
- return rd.engine in cls.COMPAT_ENGINES
-
-
-class ModifierButtonsPanel:
- """Use this class to define buttons from the modifier tab of
- properties window."""
-
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "modifier"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
- @classmethod
- def poll(cls, context):
- mods = context.object.modifiers
- rd = context.scene.render
- return mods and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class MaterialButtonsPanel:
- """Use this class to define buttons from the material tab of
- properties window."""
-
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "material"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- rd = context.scene.render
- return mat and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class TextureButtonsPanel:
- """Use this class to define buttons from the texture tab of
- properties window."""
-
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "texture"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
- @classmethod
- def poll(cls, context):
- tex = context.texture
- rd = context.scene.render
- return tex and (rd.engine in cls.COMPAT_ENGINES)
-
-
-# class TextureTypePanel(TextureButtonsPanel):
-
-# @classmethod
-# def poll(cls, context):
-# tex = context.texture
-# engine = context.scene.render.engine
-# return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES))
-
-
-class ObjectButtonsPanel:
- """Use this class to define buttons from the object tab of
- properties window."""
-
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "object"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
- @classmethod
- def poll(cls, context):
- obj = context.object
- rd = context.scene.render
- return obj and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class CameraDataButtonsPanel:
- """Use this class to define buttons from the camera data tab of
- properties window."""
-
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "data"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
- @classmethod
- def poll(cls, context):
- cam = context.camera
- rd = context.scene.render
- return cam and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class WorldButtonsPanel:
- """Use this class to define buttons from the world tab of
- properties window."""
-
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "world"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
- @classmethod
- def poll(cls, context):
- wld = context.world
- rd = context.scene.render
- return wld and (rd.engine in cls.COMPAT_ENGINES)
-
-
-class TextButtonsPanel:
- """Use this class to define buttons from the side tab of
- text window."""
-
- bl_space_type = 'TEXT_EDITOR'
- bl_region_type = 'UI'
- bl_label = "POV-Ray"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
- @classmethod
- def poll(cls, context):
- text = context.space_data
- rd = context.scene.render
- return text and (rd.engine in cls.COMPAT_ENGINES)
-
-
-from bl_ui import properties_data_mesh
-
-# These panels are kept
-properties_data_mesh.DATA_PT_custom_props_mesh.COMPAT_ENGINES.add(
- 'POVRAY_RENDER'
-)
-properties_data_mesh.DATA_PT_context_mesh.COMPAT_ENGINES.add('POVRAY_RENDER')
-
-## make some native panels contextual to some object variable
-## by recreating custom panels inheriting their properties
-
-
-class PovDataButtonsPanel(properties_data_mesh.MeshButtonsPanel):
- """Use this class to define buttons from the edit data tab of
- properties window."""
-
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- POV_OBJECT_TYPES = {
- 'PLANE',
- 'BOX',
- 'SPHERE',
- 'CYLINDER',
- 'CONE',
- 'TORUS',
- 'BLOB',
- 'ISOSURFACE',
- 'SUPERELLIPSOID',
- 'SUPERTORUS',
- 'HEIGHT_FIELD',
- 'PARAMETRIC',
- 'POLYCIRCLE',
- }
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- # We use our parent class poll func too, avoids to re-define too much things...
- return (
- super(PovDataButtonsPanel, cls).poll(context)
- and obj
- and obj.pov.object_as not in cls.POV_OBJECT_TYPES
- )
-
-
-# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
-# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
-# So we simply have to explicitly copy here the interesting bits. ;)
-class DATA_PT_POV_normals(PovDataButtonsPanel, Panel):
- bl_label = properties_data_mesh.DATA_PT_normals.bl_label
-
- draw = properties_data_mesh.DATA_PT_normals.draw
-
-
-class DATA_PT_POV_texture_space(PovDataButtonsPanel, Panel):
- bl_label = properties_data_mesh.DATA_PT_texture_space.bl_label
- bl_options = properties_data_mesh.DATA_PT_texture_space.bl_options
-
- draw = properties_data_mesh.DATA_PT_texture_space.draw
-
-
-class DATA_PT_POV_vertex_groups(PovDataButtonsPanel, Panel):
- bl_label = properties_data_mesh.DATA_PT_vertex_groups.bl_label
-
- draw = properties_data_mesh.DATA_PT_vertex_groups.draw
-
-
-class DATA_PT_POV_shape_keys(PovDataButtonsPanel, Panel):
- bl_label = properties_data_mesh.DATA_PT_shape_keys.bl_label
-
- draw = properties_data_mesh.DATA_PT_shape_keys.draw
-
-
-class DATA_PT_POV_uv_texture(PovDataButtonsPanel, Panel):
- bl_label = properties_data_mesh.DATA_PT_uv_texture.bl_label
-
- draw = properties_data_mesh.DATA_PT_uv_texture.draw
-
-
-class DATA_PT_POV_vertex_colors(PovDataButtonsPanel, Panel):
- bl_label = properties_data_mesh.DATA_PT_vertex_colors.bl_label
-
- draw = properties_data_mesh.DATA_PT_vertex_colors.draw
-
-
-class DATA_PT_POV_customdata(PovDataButtonsPanel, Panel):
- bl_label = properties_data_mesh.DATA_PT_customdata.bl_label
- bl_options = properties_data_mesh.DATA_PT_customdata.bl_options
- draw = properties_data_mesh.DATA_PT_customdata.draw
-
-
-del properties_data_mesh
-
-
-################################################################################
-# from bl_ui import properties_data_light
-# for member in dir(properties_data_light):
-# subclass = getattr(properties_data_light, member)
-# try:
-# subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
-# except:
-# pass
-# del properties_data_light
-#########################LIGHTS################################
-
-from bl_ui import properties_data_light
-
-# These panels are kept
-properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add(
- 'POVRAY_RENDER'
-)
-properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER')
-
-## make some native panels contextual to some object variable
-## by recreating custom panels inheriting their properties
-class PovLampButtonsPanel(properties_data_light.DataButtonsPanel):
- """Use this class to define buttons from the light data tab of
- properties window."""
-
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- POV_OBJECT_TYPES = {'RAINBOW'}
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- # We use our parent class poll func too, avoids to re-define too much things...
- return (
- super(PovLampButtonsPanel, cls).poll(context)
- and obj
- and obj.pov.object_as not in cls.POV_OBJECT_TYPES
- )
-
-
-# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
-# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
-# So we simply have to explicitly copy here the interesting bits. ;)
-
-
-class LIGHT_PT_POV_preview(PovLampButtonsPanel, Panel):
- bl_label = properties_data_light.DATA_PT_preview.bl_label
-
- draw = properties_data_light.DATA_PT_preview.draw
-
-
-class LIGHT_PT_POV_light(PovLampButtonsPanel, Panel):
- bl_label = properties_data_light.DATA_PT_light.bl_label
-
- draw = properties_data_light.DATA_PT_light.draw
-
-
-class LIGHT_MT_POV_presets(Menu):
- """Use this class to define preset menu for pov lights."""
-
- bl_label = "Lamp Presets"
- preset_subdir = "pov/light"
- preset_operator = "script.execute_preset"
- draw = bpy.types.Menu.draw_preset
-
-
-class LIGHT_OT_POV_add_preset(AddPresetBase, Operator):
- """Use this class to define pov world buttons"""
-
- '''Add a Light Preset'''
- bl_idname = "object.light_preset_add"
- bl_label = "Add Light Preset"
- preset_menu = "LIGHT_MT_POV_presets"
-
- # variable used for all preset values
- preset_defines = ["lightdata = bpy.context.object.data"]
-
- # properties to store in the preset
- preset_values = ["lightdata.type", "lightdata.color"]
-
- # where to store the preset
- preset_subdir = "pov/light"
-
-
-# Draw into the existing light panel
-def light_panel_func(self, context):
- layout = self.layout
-
- row = layout.row(align=True)
- row.menu(LIGHT_MT_POV_presets.__name__, text=LIGHT_MT_POV_presets.bl_label)
- row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='ADD')
- row.operator(
- LIGHT_OT_POV_add_preset.bl_idname, text="", icon='REMOVE'
- ).remove_active = True
-
-
-'''#TORECREATE##DEPRECATED#
-class LIGHT_PT_POV_sunsky(PovLampButtonsPanel, Panel):
- bl_label = properties_data_light.DATA_PT_sunsky.bl_label
-
- @classmethod
- def poll(cls, context):
- lamp = context.light
- engine = context.scene.render.engine
- return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES)
-
- draw = properties_data_light.DATA_PT_sunsky.draw
-
-'''
-
-
-class LIGHT_PT_POV_shadow(PovLampButtonsPanel, Panel):
- bl_label = "Shadow"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- lamp = context.lamp
- engine = context.scene.render.engine
- return lamp and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- lamp = context.lamp
-
- layout.row().prop(lamp, "shadow_method", expand=True)
-
- split = layout.split()
-
- col = split.column()
- sub = col.column()
- sub.prop(lamp, "spot_size", text="Size")
- sub.prop(lamp, "spot_blend", text="Blend", slider=True)
- col.prop(lamp, "use_square")
- col.prop(lamp, "show_cone")
-
- col = split.column()
-
- col.active = (
- lamp.shadow_method != 'BUFFER_SHADOW'
- or lamp.shadow_buffer_type != 'DEEP'
- )
- col.prop(lamp, "use_halo")
- sub = col.column(align=True)
- sub.active = lamp.use_halo
- sub.prop(lamp, "halo_intensity", text="Intensity")
- if lamp.shadow_method == 'BUFFER_SHADOW':
- sub.prop(lamp, "halo_step", text="Step")
- if lamp.shadow_method == 'NOSHADOW' and lamp.type == 'AREA':
- split = layout.split()
-
- col = split.column()
- col.label(text="Form factor sampling:")
-
- sub = col.row(align=True)
-
- if lamp.shape == 'SQUARE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
- elif lamp.shape == 'RECTANGLE':
- sub.prop(lamp.pov, "shadow_ray_samples_x", text="Samples X")
- sub.prop(lamp.pov, "shadow_ray_samples_y", text="Samples Y")
-
- if lamp.shadow_method != 'NOSHADOW':
- split = layout.split()
-
- col = split.column()
- col.prop(lamp, "shadow_color", text="")
-
- col = split.column()
- col.prop(lamp, "use_shadow_layer", text="This Layer Only")
- col.prop(lamp, "use_only_shadow")
-
- if lamp.shadow_method == 'RAY_SHADOW':
- split = layout.split()
-
- col = split.column()
- col.label(text="Sampling:")
-
- if lamp.type in {'POINT', 'SUN', 'SPOT'}:
- sub = col.row()
-
- sub.prop(lamp, "shadow_ray_samples", text="Samples")
- sub.prop(lamp, "shadow_soft_size", text="Soft Size")
-
- elif lamp.type == 'AREA':
- sub = col.row(align=True)
-
- if lamp.shape == 'SQUARE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
- elif lamp.shape == 'RECTANGLE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples X")
- sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y")
-
-
-'''
- if lamp.shadow_method == 'NOSHADOW' and lamp.type == 'AREA':
- split = layout.split()
-
- col = split.column()
- col.label(text="Form factor sampling:")
-
- sub = col.row(align=True)
-
- if lamp.shape == 'SQUARE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
- elif lamp.shape == 'RECTANGLE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples X")
- sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y")
-
- if lamp.shadow_method != 'NOSHADOW':
- split = layout.split()
-
- col = split.column()
- col.prop(lamp, "shadow_color", text="")
-
- col = split.column()
- col.prop(lamp, "use_shadow_layer", text="This Layer Only")
- col.prop(lamp, "use_only_shadow")
-
- if lamp.shadow_method == 'RAY_SHADOW':
- split = layout.split()
-
- col = split.column()
- col.label(text="Sampling:")
-
- if lamp.type in {'POINT', 'SUN', 'SPOT'}:
- sub = col.row()
-
- sub.prop(lamp, "shadow_ray_samples", text="Samples")
- sub.prop(lamp, "shadow_soft_size", text="Soft Size")
-
- elif lamp.type == 'AREA':
- sub = col.row(align=True)
-
- if lamp.shape == 'SQUARE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
- elif lamp.shape == 'RECTANGLE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples X")
- sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y")
-
- col.row().prop(lamp, "shadow_ray_sample_method", expand=True)
-
- if lamp.shadow_ray_sample_method == 'ADAPTIVE_QMC':
- layout.prop(lamp, "shadow_adaptive_threshold", text="Threshold")
-
- if lamp.type == 'AREA' and lamp.shadow_ray_sample_method == 'CONSTANT_JITTERED':
- row = layout.row()
- row.prop(lamp, "use_umbra")
- row.prop(lamp, "use_dither")
- row.prop(lamp, "use_jitter")
-
- elif lamp.shadow_method == 'BUFFER_SHADOW':
- col = layout.column()
- col.label(text="Buffer Type:")
- col.row().prop(lamp, "shadow_buffer_type", expand=True)
-
- if lamp.shadow_buffer_type in {'REGULAR', 'HALFWAY', 'DEEP'}:
- split = layout.split()
-
- col = split.column()
- col.label(text="Filter Type:")
- col.prop(lamp, "shadow_filter_type", text="")
- sub = col.column(align=True)
- sub.prop(lamp, "shadow_buffer_soft", text="Soft")
- sub.prop(lamp, "shadow_buffer_bias", text="Bias")
-
- col = split.column()
- col.label(text="Sample Buffers:")
- col.prop(lamp, "shadow_sample_buffers", text="")
- sub = col.column(align=True)
- sub.prop(lamp, "shadow_buffer_size", text="Size")
- sub.prop(lamp, "shadow_buffer_samples", text="Samples")
- if lamp.shadow_buffer_type == 'DEEP':
- col.prop(lamp, "compression_threshold")
-
- elif lamp.shadow_buffer_type == 'IRREGULAR':
- layout.prop(lamp, "shadow_buffer_bias", text="Bias")
-
- split = layout.split()
-
- col = split.column()
- col.prop(lamp, "use_auto_clip_start", text="Autoclip Start")
- sub = col.column()
- sub.active = not lamp.use_auto_clip_start
- sub.prop(lamp, "shadow_buffer_clip_start", text="Clip Start")
-
- col = split.column()
- col.prop(lamp, "use_auto_clip_end", text="Autoclip End")
- sub = col.column()
- sub.active = not lamp.use_auto_clip_end
- sub.prop(lamp, "shadow_buffer_clip_end", text=" Clip End")
-'''
-
-
-class LIGHT_PT_POV_area(PovLampButtonsPanel, Panel):
- bl_label = properties_data_light.DATA_PT_area.bl_label
-
- @classmethod
- def poll(cls, context):
- lamp = context.light
- engine = context.scene.render.engine
- return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES)
-
- draw = properties_data_light.DATA_PT_area.draw
-
-
-class LIGHT_PT_POV_spot(PovLampButtonsPanel, Panel):
- bl_label = properties_data_light.DATA_PT_spot.bl_label
-
- @classmethod
- def poll(cls, context):
- lamp = context.light
- engine = context.scene.render.engine
- return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
-
- draw = properties_data_light.DATA_PT_spot.draw
-
-
-class LIGHT_PT_POV_falloff_curve(PovLampButtonsPanel, Panel):
- bl_label = properties_data_light.DATA_PT_falloff_curve.bl_label
- bl_options = properties_data_light.DATA_PT_falloff_curve.bl_options
-
- @classmethod
- def poll(cls, context):
- lamp = context.light
- engine = context.scene.render.engine
-
- return (
- lamp
- and lamp.type in {'POINT', 'SPOT'}
- and lamp.falloff_type == 'CUSTOM_CURVE'
- ) and (engine in cls.COMPAT_ENGINES)
-
- draw = properties_data_light.DATA_PT_falloff_curve.draw
-
-
-class OBJECT_PT_POV_rainbow(PovLampButtonsPanel, Panel):
- """Use this class to define buttons from the rainbow panel of
- properties window. inheriting lamp buttons panel class"""
-
- bl_label = "POV-Ray Rainbow"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- # bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- return (
- obj
- and obj.pov.object_as == 'RAINBOW'
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- col = layout.column()
-
- if obj.pov.object_as == 'RAINBOW':
- if obj.pov.unlock_parameters == False:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Exported parameters below",
- icon='LOCKED',
- )
- col.label(
- text="Rainbow projection angle: " + str(obj.data.spot_size)
- )
- col.label(text="Rainbow width: " + str(obj.data.spot_blend))
- col.label(
- text="Rainbow distance: "
- + str(obj.data.shadow_buffer_clip_start)
- )
- col.label(text="Rainbow arc angle: " + str(obj.pov.arc_angle))
- col.label(
- text="Rainbow falloff angle: " + str(obj.pov.falloff_angle)
- )
-
- else:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Edit exported parameters",
- icon='UNLOCKED',
- )
- col.label(text="3D view proxy may get out of synch")
- col.active = obj.pov.unlock_parameters
-
- layout.operator(
- "pov.cone_update", text="Update", icon="MESH_CONE"
- )
-
- # col.label(text="Parameters:")
- col.prop(obj.data, "spot_size", text="Rainbow Projection Angle")
- col.prop(obj.data, "spot_blend", text="Rainbow width")
- col.prop(
- obj.data,
- "shadow_buffer_clip_start",
- text="Visibility distance",
- )
- col.prop(obj.pov, "arc_angle")
- col.prop(obj.pov, "falloff_angle")
-
-
-del properties_data_light
-###############################################################################
-
-
-class WORLD_PT_POV_world(WorldButtonsPanel, Panel):
- """Use this class to define pov world buttons"""
-
- bl_label = "World"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- world = context.world.pov
-
- row = layout.row(align=True)
- row.menu(
- WORLD_MT_POV_presets.__name__, text=WORLD_MT_POV_presets.bl_label
- )
- row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='ADD')
- row.operator(
- WORLD_OT_POV_add_preset.bl_idname, text="", icon='REMOVE'
- ).remove_active = True
-
- row = layout.row()
- row.prop(world, "use_sky_paper")
- row.prop(world, "use_sky_blend")
- row.prop(world, "use_sky_real")
-
- row = layout.row()
- row.column().prop(world, "horizon_color")
- col = row.column()
- col.prop(world, "zenith_color")
- col.active = world.use_sky_blend
- row.column().prop(world, "ambient_color")
-
- # row = layout.row()
- # row.prop(world, "exposure") #Re-implement later as a light multiplier
- # row.prop(world, "color_range")
-
-
-class WORLD_PT_POV_mist(WorldButtonsPanel, Panel):
- """Use this class to define pov mist buttons."""
-
- bl_label = "Mist"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw_header(self, context):
- world = context.world
-
- self.layout.prop(world.mist_settings, "use_mist", text="")
-
- def draw(self, context):
- layout = self.layout
-
- world = context.world
-
- layout.active = world.mist_settings.use_mist
-
- split = layout.split()
-
- col = split.column()
- col.prop(world.mist_settings, "intensity")
- col.prop(world.mist_settings, "start")
-
- col = split.column()
- col.prop(world.mist_settings, "depth")
- col.prop(world.mist_settings, "height")
-
- layout.prop(world.mist_settings, "falloff")
-
-
-class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
- """Use this class to define pov ini settingss buttons."""
- bl_options = {'DEFAULT_CLOSED'}
- bl_label = "Auto Start"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw_header(self, context):
- scene = context.scene
- if scene.pov.tempfiles_enable:
- self.layout.prop(
- scene.pov, "tempfiles_enable", text="", icon='AUTO'
- )
- else:
- self.layout.prop(
- scene.pov, "tempfiles_enable", text="", icon='CONSOLE'
- )
-
- def draw(self, context):
-
- layout = self.layout
-
- scene = context.scene
-
- layout.active = scene.pov.max_trace_level != 0
- split = layout.split()
-
- col = split.column()
- col.label(text="Command line switches:")
- col.prop(scene.pov, "command_line_switches", text="")
- split = layout.split()
-
- #layout.active = not scene.pov.tempfiles_enable
- if not scene.pov.tempfiles_enable:
- split.prop(scene.pov, "deletefiles_enable", text="Delete files")
- split.prop(scene.pov, "pov_editor", text="POV Editor")
-
- col = layout.column()
- col.prop(scene.pov, "scene_name", text="Name")
- col.prop(scene.pov, "scene_path", text="Path to files")
- # col.prop(scene.pov, "scene_path", text="Path to POV-file")
- # col.prop(scene.pov, "renderimage_path", text="Path to image")
-
- split = layout.split()
- split.prop(scene.pov, "indentation_character", text="Indent")
- if scene.pov.indentation_character == 'SPACE':
- split.prop(scene.pov, "indentation_spaces", text="Spaces")
-
- row = layout.row()
- row.prop(scene.pov, "comments_enable", text="Comments")
- row.prop(scene.pov, "list_lf_enable", text="Line breaks in lists")
-
-
-class RENDER_PT_POV_render_settings(RenderButtonsPanel, Panel):
- """Use this class to define pov render settings buttons."""
-
- bl_label = "Global Settings"
- bl_icon = 'SETTINGS'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw_header(self, context):
- scene = context.scene
- if scene.pov.global_settings_advanced:
- self.layout.prop(
- scene.pov, "global_settings_advanced", text="", icon='SETTINGS'
- )
- else:
- self.layout.prop(
- scene.pov,
- "global_settings_advanced",
- text="",
- icon='PREFERENCES',
- )
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
- rd = context.scene.render
- # layout.active = (scene.pov.max_trace_level != 0)
-
- if sys.platform[:3] != "win":
- layout.prop(
- scene.pov, "sdl_window_enable", text="POV-Ray SDL Window"
- )
-
- col = layout.column()
- col.label(text="Main Path Tracing:")
- col.prop(scene.pov, "max_trace_level", text="Ray Depth")
- align = True
- layout.active = scene.pov.global_settings_advanced
- # Deprecated (autodetected in pov3.8):
- # layout.prop(scene.pov, "charset")
- row = layout.row(align=align)
- row.prop(scene.pov, "adc_bailout")
- row = layout.row(align=align)
- row.prop(scene.pov, "ambient_light")
- row = layout.row(align=align)
- row.prop(scene.pov, "irid_wavelength")
- row = layout.row(align=align)
- row.prop(scene.pov, "max_intersections")
- row = layout.row(align=align)
- row.prop(scene.pov, "number_of_waves")
- row = layout.row(align=align)
- row.prop(scene.pov, "noise_generator")
-
- split = layout.split()
- split.label(text="Shading:")
- split = layout.split()
-
- row = split.row(align=align)
- row.prop(scene.pov, "use_shadows")
- row.prop(scene.pov, "alpha_mode")
-
-
-class RENDER_PT_POV_photons(RenderButtonsPanel, Panel):
- """Use this class to define pov photons buttons."""
-
- bl_label = "Photons"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- # def draw_header(self, context):
- # self.layout.label(icon='SETTINGS')
-
- def draw_header(self, context):
- scene = context.scene
- if scene.pov.photon_enable:
- self.layout.prop(
- scene.pov, "photon_enable", text="", icon='PMARKER_ACT'
- )
- else:
- self.layout.prop(
- scene.pov, "photon_enable", text="", icon='PMARKER'
- )
-
- def draw(self, context):
- scene = context.scene
- layout = self.layout
- layout.active = scene.pov.photon_enable
- col = layout.column()
- # col.label(text="Global Photons:")
- col.prop(scene.pov, "photon_max_trace_level", text="Photon Depth")
-
- split = layout.split()
-
- col = split.column()
- col.prop(scene.pov, "photon_spacing", text="Spacing")
- col.prop(scene.pov, "photon_gather_min")
-
- col = split.column()
- col.prop(scene.pov, "photon_adc_bailout", text="Photon ADC")
- col.prop(scene.pov, "photon_gather_max")
-
- box = layout.box()
- box.label(text='Photon Map File:')
- row = box.row()
- row.prop(scene.pov, "photon_map_file_save_load", expand=True)
- if scene.pov.photon_map_file_save_load in {'save'}:
- box.prop(scene.pov, "photon_map_dir")
- box.prop(scene.pov, "photon_map_filename")
- if scene.pov.photon_map_file_save_load in {'load'}:
- box.prop(scene.pov, "photon_map_file")
- # end main photons
-
-
-class RENDER_PT_POV_antialias(RenderButtonsPanel, Panel):
- """Use this class to define pov antialiasing buttons."""
-
- bl_label = "Anti-Aliasing"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw_header(self, context):
- prefs = bpy.context.preferences.addons[__package__].preferences
- scene = context.scene
- if (
- prefs.branch_feature_set_povray != 'uberpov'
- and scene.pov.antialias_method == '2'
- ):
- self.layout.prop(
- scene.pov, "antialias_enable", text="", icon='ERROR'
- )
- elif scene.pov.antialias_enable:
- self.layout.prop(
- scene.pov, "antialias_enable", text="", icon='ANTIALIASED'
- )
- else:
- self.layout.prop(
- scene.pov, "antialias_enable", text="", icon='ALIASED'
- )
-
- def draw(self, context):
- prefs = bpy.context.preferences.addons[__package__].preferences
- layout = self.layout
- scene = context.scene
-
- layout.active = scene.pov.antialias_enable
-
- row = layout.row()
- row.prop(scene.pov, "antialias_method", text="")
-
- if (
- prefs.branch_feature_set_povray != 'uberpov'
- and scene.pov.antialias_method == '2'
- ):
- col = layout.column()
- col.alignment = 'CENTER'
- col.label(text="Stochastic Anti Aliasing is")
- col.label(text="Only Available with UberPOV")
- col.label(text="Feature Set in User Preferences.")
- col.label(text="Using Type 2 (recursive) instead")
- else:
- row.prop(scene.pov, "jitter_enable", text="Jitter")
-
- split = layout.split()
- col = split.column()
- col.prop(scene.pov, "antialias_depth", text="AA Depth")
- sub = split.column()
- sub.prop(scene.pov, "jitter_amount", text="Jitter Amount")
- if scene.pov.jitter_enable:
- sub.enabled = True
- else:
- sub.enabled = False
-
- row = layout.row()
- row.prop(scene.pov, "antialias_threshold", text="AA Threshold")
- row.prop(scene.pov, "antialias_gamma", text="AA Gamma")
-
- if prefs.branch_feature_set_povray == 'uberpov':
- row = layout.row()
- row.prop(
- scene.pov, "antialias_confidence", text="AA Confidence"
- )
- if scene.pov.antialias_method == '2':
- row.enabled = True
- else:
- row.enabled = False
-
-
-class RENDER_PT_POV_radiosity(RenderButtonsPanel, Panel):
- """Use this class to define pov radiosity buttons."""
-
- bl_label = "Diffuse Radiosity"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw_header(self, context):
- scene = context.scene
- if scene.pov.radio_enable:
- self.layout.prop(
- scene.pov,
- "radio_enable",
- text="",
- icon='OUTLINER_OB_LIGHTPROBE',
- )
- else:
- self.layout.prop(
- scene.pov, "radio_enable", text="", icon='LIGHTPROBE_CUBEMAP'
- )
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
-
- layout.active = scene.pov.radio_enable
-
- split = layout.split()
-
- col = split.column()
- col.prop(scene.pov, "radio_count", text="Rays")
- col.prop(scene.pov, "radio_recursion_limit", text="Recursions")
-
- split.prop(scene.pov, "radio_error_bound", text="Error Bound")
-
- layout.prop(scene.pov, "radio_display_advanced")
-
- if scene.pov.radio_display_advanced:
- split = layout.split()
-
- col = split.column()
- col.prop(scene.pov, "radio_adc_bailout", slider=True)
- col.prop(scene.pov, "radio_minimum_reuse", text="Min Reuse")
- col.prop(scene.pov, "radio_gray_threshold", slider=True)
- col.prop(scene.pov, "radio_pretrace_start", slider=True)
- col.prop(scene.pov, "radio_low_error_factor", slider=True)
-
- col = split.column()
- col.prop(scene.pov, "radio_brightness")
- col.prop(scene.pov, "radio_maximum_reuse", text="Max Reuse")
- col.prop(scene.pov, "radio_nearest_count")
- col.prop(scene.pov, "radio_pretrace_end", slider=True)
-
- col = layout.column()
- col.label(text="Estimation Influence:")
- col.prop(scene.pov, "radio_always_sample")
- col.prop(scene.pov, "radio_normal")
- col.prop(scene.pov, "radio_media")
- col.prop(scene.pov, "radio_subsurface")
-
-
-class POV_RADIOSITY_MT_presets(Menu):
- """Use this class to define pov radiosity presets menu."""
-
- bl_label = "Radiosity Presets"
- preset_subdir = "pov/radiosity"
- preset_operator = "script.execute_preset"
- draw = bpy.types.Menu.draw_preset
-
-
-class RENDER_OT_POV_radiosity_add_preset(AddPresetBase, Operator):
- """Use this class to define pov radiosity add presets button"""
-
- '''Add a Radiosity Preset'''
- bl_idname = "scene.radiosity_preset_add"
- bl_label = "Add Radiosity Preset"
- preset_menu = "POV_RADIOSITY_MT_presets"
-
- # variable used for all preset values
- preset_defines = ["scene = bpy.context.scene"]
-
- # properties to store in the preset
- preset_values = [
- "scene.pov.radio_display_advanced",
- "scene.pov.radio_adc_bailout",
- "scene.pov.radio_always_sample",
- "scene.pov.radio_brightness",
- "scene.pov.radio_count",
- "scene.pov.radio_error_bound",
- "scene.pov.radio_gray_threshold",
- "scene.pov.radio_low_error_factor",
- "scene.pov.radio_media",
- "scene.pov.radio_subsurface",
- "scene.pov.radio_minimum_reuse",
- "scene.pov.radio_maximum_reuse",
- "scene.pov.radio_nearest_count",
- "scene.pov.radio_normal",
- "scene.pov.radio_recursion_limit",
- "scene.pov.radio_pretrace_start",
- "scene.pov.radio_pretrace_end",
- ]
-
- # where to store the preset
- preset_subdir = "pov/radiosity"
-
-
-# Draw into an existing panel
-def rad_panel_func(self, context):
- layout = self.layout
-
- row = layout.row(align=True)
- row.menu(
- POV_RADIOSITY_MT_presets.__name__,
- text=POV_RADIOSITY_MT_presets.bl_label,
- )
- row.operator(
- RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='ADD'
- )
- row.operator(
- RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='REMOVE'
- ).remove_active = True
-
-
-class RENDER_PT_POV_media(WorldButtonsPanel, Panel):
- """Use this class to define a pov global atmospheric media buttons."""
-
- bl_label = "Atmosphere Media"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw_header(self, context):
- scene = context.scene
-
- self.layout.prop(scene.pov, "media_enable", text="")
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
-
- layout.active = scene.pov.media_enable
-
- col = layout.column()
- col.prop(scene.pov, "media_scattering_type", text="")
- col = layout.column()
- col.prop(scene.pov, "media_samples", text="Samples")
- split = layout.split()
- col = split.column(align=True)
- col.label(text="Scattering:")
- col.prop(scene.pov, "media_diffusion_scale")
- col.prop(scene.pov, "media_diffusion_color", text="")
- col = split.column(align=True)
- col.label(text="Absorption:")
- col.prop(scene.pov, "media_absorption_scale")
- col.prop(scene.pov, "media_absorption_color", text="")
- if scene.pov.media_scattering_type == '5':
- col = layout.column()
- col.prop(scene.pov, "media_eccentricity", text="Eccentricity")
-
-
-##class RENDER_PT_povray_baking(RenderButtonsPanel, Panel):
-## bl_label = "Baking"
-## COMPAT_ENGINES = {'POVRAY_RENDER'}
-##
-## def draw_header(self, context):
-## scene = context.scene
-##
-## self.layout.prop(scene.pov, "baking_enable", text="")
-##
-## def draw(self, context):
-## layout = self.layout
-##
-## scene = context.scene
-## rd = scene.render
-##
-## layout.active = scene.pov.baking_enable
-
-
-class MODIFIERS_PT_POV_modifiers(ModifierButtonsPanel, Panel):
- """Use this class to define pov modifier buttons. (For booleans)"""
-
- bl_label = "POV-Ray"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- # def draw_header(self, context):
- # scene = context.scene
- # self.layout.prop(scene.pov, "boolean_mod", text="")
-
- def draw(self, context):
- scene = context.scene
- layout = self.layout
- ob = context.object
- mod = ob.modifiers
- col = layout.column()
- # Find Boolean Modifiers for displaying CSG option
- onceCSG = 0
- for mod in ob.modifiers:
- if onceCSG == 0:
- if mod:
- if mod.type == 'BOOLEAN':
- col.prop(ob.pov, "boolean_mod")
- onceCSG = 1
-
- if ob.pov.boolean_mod == "POV":
- split = layout.split()
- col = layout.column()
- # Inside Vector for CSG
- col.prop(ob.pov, "inside_vector")
-
-
-class MATERIAL_MT_POV_sss_presets(Menu):
- """Use this class to define pov sss preset menu."""
-
- bl_label = "SSS Presets"
- preset_subdir = "pov/material/sss"
- preset_operator = "script.execute_preset"
- draw = bpy.types.Menu.draw_preset
-
-
-class MATERIAL_OT_POV_sss_add_preset(AddPresetBase, Operator):
- """Add an SSS Preset"""
-
- bl_idname = "material.sss_preset_add"
- bl_label = "Add SSS Preset"
- preset_menu = "MATERIAL_MT_POV_sss_presets"
-
- # variable used for all preset values
- preset_defines = ["material = bpy.context.material"]
-
- # properties to store in the preset
- preset_values = [
- "material.pov_subsurface_scattering.radius",
- "material.pov_subsurface_scattering.color",
- ]
-
- # where to store the preset
- preset_subdir = "pov/material/sss"
-
-
-class MATERIAL_PT_POV_sss(MaterialButtonsPanel, Panel):
- """Use this class to define pov sss buttons panel."""
-
- bl_label = "Subsurface Scattering"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return (
- check_material(mat)
- and (mat.pov.type in {'SURFACE', 'WIRE'})
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw_header(self, context):
- mat = context.material # FORMERLY : #active_node_mat(context.material)
- sss = mat.pov_subsurface_scattering
-
- self.layout.active = not mat.pov.use_shadeless
- self.layout.prop(sss, "use", text="")
-
- def draw(self, context):
- layout = self.layout
-
- mat = context.material # FORMERLY : #active_node_mat(context.material)
- sss = mat.pov_subsurface_scattering
-
- layout.active = (sss.use) and (not mat.pov.use_shadeless)
-
- row = layout.row().split()
- sub = row.row(align=True).split(align=True, factor=0.75)
- sub.menu(
- MATERIAL_MT_POV_sss_presets.__name__,
- text=MATERIAL_MT_POV_sss_presets.bl_label,
- )
- sub.operator(
- MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='ADD'
- )
- sub.operator(
- MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='REMOVE'
- ).remove_active = True
-
- split = layout.split()
-
- col = split.column()
- col.prop(sss, "ior")
- col.prop(sss, "scale")
- col.prop(sss, "color", text="")
- col.prop(sss, "radius", text="RGB Radius", expand=True)
-
- col = split.column()
- sub = col.column(align=True)
- sub.label(text="Blend:")
- sub.prop(sss, "color_factor", text="Color")
- sub.prop(sss, "texture_factor", text="Texture")
- sub.label(text="Scattering Weight:")
- sub.prop(sss, "front")
- sub.prop(sss, "back")
- col.separator()
- col.prop(sss, "error_threshold", text="Error")
-
-
-class MATERIAL_PT_POV_activate_node(MaterialButtonsPanel, Panel):
- """Use this class to define an activate pov nodes button."""
-
- bl_label = "Activate Node Settings"
- bl_context = "material"
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- mat = context.material
- ob = context.object
- return (
- mat
- and mat.pov.type == "SURFACE"
- and (engine in cls.COMPAT_ENGINES)
- and not (mat.pov.material_use_nodes or mat.use_nodes)
- )
-
- def draw(self, context):
- layout = self.layout
- # layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
- # the above replaced with a context hook below:
- layout.operator(
- "WM_OT_context_toggle", text="Use POV-Ray Nodes", icon='NODETREE'
- ).data_path = "material.pov.material_use_nodes"
-
-
-class MATERIAL_PT_POV_active_node(MaterialButtonsPanel, Panel):
- """Use this class to show pov active node properties buttons."""
-
- bl_label = "Active Node Settings"
- bl_context = "material"
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- mat = context.material
- ob = context.object
- return (
- mat
- and mat.pov.type == "SURFACE"
- and (engine in cls.COMPAT_ENGINES)
- and mat.pov.material_use_nodes
- )
-
- def draw(self, context):
- layout = self.layout
- mat = context.material
- node_tree = mat.node_tree
- if node_tree:
- node = node_tree.nodes.active
- if mat.use_nodes:
- if node:
- layout.prop(mat.pov, "material_active_node")
- if node.bl_idname == "PovrayMaterialNode":
- layout.context_pointer_set("node", node)
- if hasattr(node, "draw_buttons_ext"):
- node.draw_buttons_ext(context, layout)
- elif hasattr(node, "draw_buttons"):
- node.draw_buttons(context, layout)
- value_inputs = [
- socket
- for socket in node.inputs
- if socket.enabled and not socket.is_linked
- ]
- if value_inputs:
- layout.separator()
- layout.label(text="Inputs:")
- for socket in value_inputs:
- row = layout.row()
- socket.draw(context, row, node, socket.name)
- else:
- layout.context_pointer_set("node", node)
- if hasattr(node, "draw_buttons_ext"):
- node.draw_buttons_ext(context, layout)
- elif hasattr(node, "draw_buttons"):
- node.draw_buttons(context, layout)
- value_inputs = [
- socket
- for socket in node.inputs
- if socket.enabled and not socket.is_linked
- ]
- if value_inputs:
- layout.separator()
- layout.label(text="Inputs:")
- for socket in value_inputs:
- row = layout.row()
- socket.draw(context, row, node, socket.name)
- else:
- layout.label(text="No active nodes!")
-
-class MATERIAL_PT_POV_specular(MaterialButtonsPanel, Panel):
- """Use this class to define standard material specularity (highlights) buttons."""
-
- bl_label = "Specular"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return (
- check_material(mat)
- and (mat.pov.type in {'SURFACE', 'WIRE'})
- and (engine in cls.COMPAT_ENGINES)
- )
- def draw(self, context):
- layout = self.layout
-
- mat = context.material.pov
-
- layout.active = (not mat.use_shadeless)
-
- split = layout.split()
-
- col = split.column()
- col.prop(mat, "specular_color", text="")
- col.prop(mat, "specular_intensity", text="Intensity")
-
- col = split.column()
- col.prop(mat, "specular_shader", text="")
- col.prop(mat, "use_specular_ramp", text="Ramp")
-
- col = layout.column()
- if mat.specular_shader in {'COOKTORR', 'PHONG'}:
- col.prop(mat, "specular_hardness", text="Hardness")
- elif mat.specular_shader == 'BLINN':
- row = col.row()
- row.prop(mat, "specular_hardness", text="Hardness")
- row.prop(mat, "specular_ior", text="IOR")
- elif mat.specular_shader == 'WARDISO':
- col.prop(mat, "specular_slope", text="Slope")
- elif mat.specular_shader == 'TOON':
- row = col.row()
- row.prop(mat, "specular_toon_size", text="Size")
- row.prop(mat, "specular_toon_smooth", text="Smooth")
-
- if mat.use_specular_ramp:
- layout.separator()
- layout.template_color_ramp(mat, "specular_ramp", expand=True)
- layout.separator()
-
- row = layout.row()
- row.prop(mat, "specular_ramp_input", text="Input")
- row.prop(mat, "specular_ramp_blend", text="Blend")
-
- layout.prop(mat, "specular_ramp_factor", text="Factor")
-
-class MATERIAL_PT_POV_mirror(MaterialButtonsPanel, Panel):
- """Use this class to define standard material reflectivity (mirror) buttons."""
-
- bl_label = "Mirror"
- bl_options = {'DEFAULT_CLOSED'}
- bl_idname = "MATERIAL_PT_POV_raytrace_mirror"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return (
- check_material(mat)
- and (mat.pov.type in {'SURFACE', 'WIRE'})
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw_header(self, context):
- mat = context.material
- raym = mat.pov_raytrace_mirror
-
- self.layout.prop(raym, "use", text="")
-
- def draw(self, context):
- layout = self.layout
-
- mat = (
- context.material
- ) # Formerly : #mat = active_node_mat(context.material)
- raym = mat.pov_raytrace_mirror
-
- layout.active = raym.use
-
- split = layout.split()
-
- col = split.column()
- col.prop(raym, "reflect_factor")
- col.prop(raym, "mirror_color", text="")
-
- col = split.column()
- col.prop(raym, "fresnel")
- sub = col.column()
- sub.active = raym.fresnel > 0.0
- sub.prop(raym, "fresnel_factor", text="Blend")
-
- split = layout.split()
-
- col = split.column()
- col.separator()
- col.prop(raym, "depth")
- col.prop(raym, "distance", text="Max Dist")
- col.separator()
- sub = col.split(factor=0.4)
- sub.active = raym.distance > 0.0
- sub.label(text="Fade To:")
- sub.prop(raym, "fade_to", text="")
-
- col = split.column()
- col.label(text="Gloss:")
- col.prop(raym, "gloss_factor", text="Amount")
- sub = col.column()
- sub.active = raym.gloss_factor < 1.0
- sub.prop(raym, "gloss_threshold", text="Threshold")
- sub.prop(raym, "gloss_samples", text="Noise")
- sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
-
-
-class MATERIAL_PT_POV_transp(MaterialButtonsPanel, Panel):
- """Use this class to define pov material transparency (alpha) buttons."""
-
- bl_label = "Transparency"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return (
- check_material(mat)
- and (mat.pov.type in {'SURFACE', 'WIRE'})
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw_header(self, context):
- mat = context.material
-
- if simple_material(mat):
- self.layout.prop(mat.pov, "use_transparency", text="")
-
- def draw(self, context):
- layout = self.layout
-
- base_mat = context.material
- mat = context.material # FORMERLY active_node_mat(context.material)
- rayt = mat.pov_raytrace_transparency
-
- if simple_material(base_mat):
- row = layout.row()
- row.active = mat.pov.use_transparency
- row.prop(mat.pov, "transparency_method", expand=True)
-
- split = layout.split()
- split.active = base_mat.pov.use_transparency
-
- col = split.column()
- col.prop(mat.pov, "alpha")
- row = col.row()
- row.active = (base_mat.pov.transparency_method != 'MASK') and (
- not mat.pov.use_shadeless
- )
- row.prop(mat.pov, "specular_alpha", text="Specular")
-
- col = split.column()
- col.active = not mat.pov.use_shadeless
- col.prop(rayt, "fresnel")
- sub = col.column()
- sub.active = rayt.fresnel > 0.0
- sub.prop(rayt, "fresnel_factor", text="Blend")
-
- if base_mat.pov.transparency_method == 'RAYTRACE':
- layout.separator()
- split = layout.split()
- split.active = base_mat.pov.use_transparency
-
- col = split.column()
- col.prop(rayt, "ior")
- col.prop(rayt, "filter")
- col.prop(rayt, "falloff")
- col.prop(rayt, "depth_max")
- col.prop(rayt, "depth")
-
- col = split.column()
- col.label(text="Gloss:")
- col.prop(rayt, "gloss_factor", text="Amount")
- sub = col.column()
- sub.active = rayt.gloss_factor < 1.0
- sub.prop(rayt, "gloss_threshold", text="Threshold")
- sub.prop(rayt, "gloss_samples", text="Samples")
-
-
-class MATERIAL_PT_POV_reflection(MaterialButtonsPanel, Panel):
- """Use this class to define more pov specific reflectivity buttons."""
-
- bl_label = "POV-Ray Reflection"
- bl_parent_id = "MATERIAL_PT_POV_raytrace_mirror"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- mat = context.material
- ob = context.object
- return (
- mat
- and mat.pov.type == "SURFACE"
- and (engine in cls.COMPAT_ENGINES)
- and not (mat.pov.material_use_nodes or mat.use_nodes)
- )
-
- def draw(self, context):
- layout = self.layout
- mat = context.material
- col = layout.column()
- col.prop(mat.pov, "irid_enable")
- if mat.pov.irid_enable:
- col = layout.column()
- col.prop(mat.pov, "irid_amount", slider=True)
- col.prop(mat.pov, "irid_thickness", slider=True)
- col.prop(mat.pov, "irid_turbulence", slider=True)
- col.prop(mat.pov, "conserve_energy")
- col2 = col.split().column()
-
- if not mat.pov_raytrace_mirror.use:
- col2.label(text="Please Check Mirror settings :")
- col2.active = mat.pov_raytrace_mirror.use
- col2.prop(mat.pov, "mirror_use_IOR")
- if mat.pov.mirror_use_IOR:
- col2.alignment = 'CENTER'
- col2.label(text="The current Raytrace ")
- col2.label(text="Transparency IOR is: " + str(mat.pov.ior))
- col2.prop(mat.pov, "mirror_metallic")
-
-
-'''
-#group some native Blender (SSS) and POV (Fade)settings under such a parent panel?
-class MATERIAL_PT_POV_interior(MaterialButtonsPanel, Panel):
- bl_label = "POV-Ray Interior"
- bl_idname = "material.pov_interior"
- #bl_parent_id = "material.absorption"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- mat=context.material
- ob = context.object
- return mat and mat.pov.type == "SURFACE" and (engine in cls.COMPAT_ENGINES) and not (mat.pov.material_use_nodes or mat.use_nodes)
-
-
- def draw_header(self, context):
- mat = context.material
-'''
-
-
-class MATERIAL_PT_POV_fade_color(MaterialButtonsPanel, Panel):
- """Use this class to define pov fading (absorption) color buttons."""
-
- bl_label = "POV-Ray Absorption"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- # bl_parent_id = "material.pov_interior"
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- mat = context.material
- ob = context.object
- return (
- mat
- and mat.pov.type == "SURFACE"
- and (engine in cls.COMPAT_ENGINES)
- and not (mat.pov.material_use_nodes or mat.use_nodes)
- )
-
- def draw_header(self, context):
- mat = context.material
-
- self.layout.prop(mat.pov, "interior_fade_color", text="")
-
- def draw(self, context):
- layout = self.layout
- mat = context.material
- # layout.active = mat.pov.interior_fade_color
- if mat.pov.interior_fade_color != (0.0, 0.0, 0.0):
- layout.label(text="Raytrace transparency")
- layout.label(text="depth max Limit needs")
- layout.label(text="to be non zero to fade")
-
- pass
-
-
-class MATERIAL_PT_POV_caustics(MaterialButtonsPanel, Panel):
- """Use this class to define pov caustics buttons."""
-
- bl_label = "Caustics"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- mat = context.material
- ob = context.object
- return (
- mat
- and mat.pov.type == "SURFACE"
- and (engine in cls.COMPAT_ENGINES)
- and not (mat.pov.material_use_nodes or mat.use_nodes)
- )
-
- def draw_header(self, context):
- mat = context.material
- if mat.pov.caustics_enable:
- self.layout.prop(
- mat.pov, "caustics_enable", text="", icon="PMARKER_SEL"
- )
- else:
- self.layout.prop(
- mat.pov, "caustics_enable", text="", icon="PMARKER"
- )
-
- def draw(self, context):
-
- layout = self.layout
-
- mat = context.material
- layout.active = mat.pov.caustics_enable
- col = layout.column()
- if mat.pov.caustics_enable:
- col.prop(mat.pov, "refraction_caustics")
- if mat.pov.refraction_caustics:
-
- col.prop(mat.pov, "refraction_type", text="")
-
- if mat.pov.refraction_type == "1":
- col.prop(mat.pov, "fake_caustics_power", slider=True)
- elif mat.pov.refraction_type == "2":
- col.prop(mat.pov, "photons_dispersion", slider=True)
- col.prop(mat.pov, "photons_dispersion_samples", slider=True)
- col.prop(mat.pov, "photons_reflection")
-
- if (
- not mat.pov.refraction_caustics
- and not mat.pov.photons_reflection
- ):
- col = layout.column()
- col.alignment = 'CENTER'
- col.label(text="Caustics override is on, ")
- col.label(text="but you didn't chose any !")
-
-
-class MATERIAL_PT_strand(MaterialButtonsPanel, Panel):
- """Use this class to define Blender strand antialiasing buttons."""
-
- bl_label = "Strand"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return (
- mat
- and (mat.pov.type in {'SURFACE', 'WIRE', 'HALO'})
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- layout = self.layout
-
- mat = context.material # don't use node material
- tan = mat.strand
-
- split = layout.split()
-
- col = split.column()
- sub = col.column(align=True)
- sub.label(text="Size:")
- sub.prop(tan, "root_size", text="Root")
- sub.prop(tan, "tip_size", text="Tip")
- sub.prop(tan, "size_min", text="Minimum")
- sub.prop(tan, "use_blender_units")
- sub = col.column()
- sub.active = not mat.pov.use_shadeless
- sub.prop(tan, "use_tangent_shading")
- col.prop(tan, "shape")
-
- col = split.column()
- col.label(text="Shading:")
- col.prop(tan, "width_fade")
- ob = context.object
- if ob and ob.type == 'MESH':
- col.prop_search(
- tan, "uv_layer", ob.data, "tessface_uv_textures", text=""
- )
- else:
- col.prop(tan, "uv_layer", text="")
- col.separator()
- sub = col.column()
- sub.active = not mat.pov.use_shadeless
- sub.label(text="Surface diffuse:")
- sub = col.column()
- sub.prop(tan, "blend_distance", text="Distance")
-
-
-class MATERIAL_PT_POV_replacement_text(MaterialButtonsPanel, Panel):
- """Use this class to define pov custom code declared name field."""
-
- bl_label = "Custom POV Code"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- mat = context.material
-
- col = layout.column()
- col.label(text="Replace properties with:")
- col.prop(mat.pov, "replacement_text", text="")
-
-
-class TEXTURE_MT_POV_specials(Menu):
- """Use this class to define pov texture slot operations buttons."""
-
- bl_label = "Texture Specials"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator("texture.slot_copy", icon='COPYDOWN')
- layout.operator("texture.slot_paste", icon='PASTEDOWN')
-
-
-class WORLD_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
- """Use this class to show pov texture slots list.""" # XXX Not used yet
-
- index: bpy.props.IntProperty(name='index')
- def draw_item(
- self, context, layout, data, item, icon, active_data, active_propname
- ):
- world = context.scene.world # .pov
- active_data = world.pov
- # tex = context.texture #may be needed later?
-
- # We could write some code to decide which icon to use here...
- custom_icon = 'TEXTURE'
-
- ob = data
- slot = item
- # ma = slot.name
- # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- # You should always start your row layout by a label (icon + text), or a non-embossed text field,
- # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
- # We use icon_value of label, as our given icon is an integer value, not an enum ID.
- # Note "data" names should never be translated!
- if slot:
- layout.prop(
- item, "texture", text="", emboss=False, icon='TEXTURE'
- )
- else:
- layout.label(text="New", translate=False, icon_value=icon)
- # 'GRID' layout type should be as compact as possible (typically a single icon!).
- elif self.layout_type in {'GRID'}:
- layout.alignment = 'CENTER'
- layout.label(text="", icon_value=icon)
-
-
-class MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist(UIList):
- """Use this class to show pov texture slots list."""
-
- # texture_slots:
- index: bpy.props.IntProperty(name='index')
- # foo = random prop
- def draw_item(
- self, context, layout, data, item, icon, active_data, active_propname
- ):
- ob = data
- slot = item
- # ma = slot.name
- # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- # You should always start your row layout by a label (icon + text), or a non-embossed text field,
- # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
- # We use icon_value of label, as our given icon is an integer value, not an enum ID.
- # Note "data" names should never be translated!
- if slot:
- layout.prop(
- item, "texture", text="", emboss=False, icon='TEXTURE'
- )
- else:
- layout.label(text="New", translate=False, icon_value=icon)
- # 'GRID' layout type should be as compact as possible (typically a single icon!).
- elif self.layout_type in {'GRID'}:
- layout.alignment = 'CENTER'
- layout.label(text="", icon_value=icon)
-
-# Rewrite an existing class to modify.
-# register but not unregistered because
-# the modified parts concern only POVRAY_RENDER
-class TEXTURE_PT_context(TextureButtonsPanel, Panel):
- bl_label = ""
- bl_context = "texture"
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'POVRAY_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- return (
- (context.scene.texture_context
- not in('MATERIAL','WORLD','LIGHT','PARTICLES','LINESTYLE')
- or context.scene.render.engine != 'POVRAY_RENDER')
- )
- def draw(self, context):
- layout = self.layout
- tex = context.texture
- space = context.space_data
- pin_id = space.pin_id
- use_pin_id = space.use_pin_id
- user = context.texture_user
-
- col = layout.column()
-
- if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
- pin_id = None
-
- if not pin_id:
- col.template_texture_user()
-
- if user or pin_id:
- col.separator()
-
- if pin_id:
- col.template_ID(space, "pin_id")
- else:
- propname = context.texture_user_property.identifier
- col.template_ID(user, propname, new="texture.new")
-
- if tex:
- col.separator()
-
- split = col.split(factor=0.2)
- split.label(text="Type")
- split.prop(tex, "type", text="")
-
-class TEXTURE_PT_POV_context_texture(TextureButtonsPanel, Panel):
- """Use this class to show pov texture context buttons."""
-
- bl_label = ""
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- return engine in cls.COMPAT_ENGINES
- # if not (hasattr(context, "pov_texture_slot") or hasattr(context, "texture_node")):
- # return False
- return (
- context.material
- or context.scene.world
- or context.light
- or context.texture
- or context.line_style
- or context.particle_system
- or isinstance(context.space_data.pin_id, ParticleSettings)
- or context.texture_user
- ) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
- mat = context.view_layer.objects.active.active_material
- wld = context.scene.world
-
- layout.prop(scene, "texture_context", expand=True)
- if scene.texture_context == 'MATERIAL' and mat is not None:
-
- row = layout.row()
- row.template_list(
- "MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist",
- "",
- mat,
- "pov_texture_slots",
- mat.pov,
- "active_texture_index",
- rows=2,
- maxrows=16,
- type="DEFAULT"
- )
- col = row.column(align=True)
- col.operator("pov.textureslotadd", icon='ADD', text='')
- col.operator("pov.textureslotremove", icon='REMOVE', text='')
- #todo: recreate for pov_texture_slots?
- #col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
- #col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
- col.separator()
-
- if mat.pov_texture_slots:
- index = mat.pov.active_texture_index
- slot = mat.pov_texture_slots[index]
- povtex = slot.texture#slot.name
- tex = bpy.data.textures[povtex]
- col.prop(tex, 'use_fake_user', text='')
- #layout.label(text='Linked Texture data browser:')
- propname = slot.texture_search
- # if slot.texture was a pointer to texture data rather than just a name string:
- # layout.template_ID(povtex, "texture", new="texture.new")
-
- layout.prop_search(
- slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE'
- )
- try:
- bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[slot.texture_search]
- bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[slot.texture_search]
- except KeyError:
- # texture not hand-linked by user
- pass
-
- if tex:
- layout.separator()
- split = layout.split(factor=0.2)
- split.label(text="Type")
- split.prop(tex, "type", text="")
-
- # else:
- # for i in range(18): # length of material texture slots
- # mat.pov_texture_slots.add()
- elif scene.texture_context == 'WORLD' and wld is not None:
-
- row = layout.row()
- row.template_list(
- "WORLD_TEXTURE_SLOTS_UL_POV_layerlist",
- "",
- wld,
- "pov_texture_slots",
- wld.pov,
- "active_texture_index",
- rows=2,
- maxrows=16,
- type="DEFAULT"
- )
- col = row.column(align=True)
- col.operator("pov.textureslotadd", icon='ADD', text='')
- col.operator("pov.textureslotremove", icon='REMOVE', text='')
-
- #todo: recreate for pov_texture_slots?
- #col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
- #col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
- col.separator()
-
- if wld.pov_texture_slots:
- index = wld.pov.active_texture_index
- slot = wld.pov_texture_slots[index]
- povtex = slot.texture#slot.name
- tex = bpy.data.textures[povtex]
- col.prop(tex, 'use_fake_user', text='')
- #layout.label(text='Linked Texture data browser:')
- propname = slot.texture_search
- # if slot.texture was a pointer to texture data rather than just a name string:
- # layout.template_ID(povtex, "texture", new="texture.new")
-
- layout.prop_search(
- slot, 'texture_search', bpy.data, 'textures', text='', icon='TEXTURE'
- )
- try:
- bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[slot.texture_search]
- bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[slot.texture_search]
- except KeyError:
- # texture not hand-linked by user
- pass
-
- if tex:
- layout.separator()
- split = layout.split(factor=0.2)
- split.label(text="Type")
- split.prop(tex, "type", text="")
-
-# Commented out below is a reminder of what existed in Blender Internal
-# attributes need to be recreated
-'''
- slot = getattr(context, "texture_slot", None)
- node = getattr(context, "texture_node", None)
- space = context.space_data
-
- #attempt at replacing removed space_data
- mtl = getattr(context, "material", None)
- if mtl != None:
- spacedependant = mtl
- wld = getattr(context, "world", None)
- if wld != None:
- spacedependant = wld
- lgt = getattr(context, "light", None)
- if lgt != None:
- spacedependant = lgt
-
-
- #idblock = context.particle_system.settings
-
- tex = getattr(context, "texture", None)
- if tex != None:
- spacedependant = tex
-
-
-
- scene = context.scene
- idblock = scene.pov#pov_context_tex_datablock(context)
- pin_id = space.pin_id
-
- #spacedependant.use_limited_texture_context = True
-
- if space.use_pin_id and not isinstance(pin_id, Texture):
- idblock = id_tex_datablock(pin_id)
- pin_id = None
-
- if not space.use_pin_id:
- layout.row().prop(spacedependant, "texture_context", expand=True)
- pin_id = None
-
- if spacedependant.texture_context == 'OTHER':
- if not pin_id:
- layout.template_texture_user()
- user = context.texture_user
- if user or pin_id:
- layout.separator()
-
- row = layout.row()
-
- if pin_id:
- row.template_ID(space, "pin_id")
- else:
- propname = context.texture_user_property.identifier
- row.template_ID(user, propname, new="texture.new")
-
- if tex:
- split = layout.split(factor=0.2)
- if tex.use_nodes:
- if slot:
- split.label(text="Output:")
- split.prop(slot, "output_node", text="")
- else:
- split.label(text="Type:")
- split.prop(tex, "type", text="")
- return
-
- tex_collection = (pin_id is None) and (node is None) and (spacedependant.texture_context not in ('LINESTYLE','OTHER'))
-
- if tex_collection:
-
- pov = getattr(context, "pov", None)
- active_texture_index = getattr(spacedependant, "active_texture_index", None)
- print (pov)
- print(idblock)
- print(active_texture_index)
- row = layout.row()
-
- row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots",
- idblock, "active_texture_index", rows=2, maxrows=16, type="DEFAULT")
-
- # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
- # world.texture_slots, world, "active_texture_index", rows=2)
-
- col = row.column(align=True)
- col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
- col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
- col.menu("TEXTURE_MT_POV_specials", icon='DOWNARROW_HLT', text="")
-
- if tex_collection:
- layout.template_ID(idblock, "active_texture", new="texture.new")
- elif node:
- layout.template_ID(node, "texture", new="texture.new")
- elif idblock:
- layout.template_ID(idblock, "texture", new="texture.new")
-
- if pin_id:
- layout.template_ID(space, "pin_id")
-
- if tex:
- split = layout.split(factor=0.2)
- if tex.use_nodes:
- if slot:
- split.label(text="Output:")
- split.prop(slot, "output_node", text="")
- else:
- split.label(text="Type:")
-'''
-
-
-class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
- """Use this class to show pov color ramps."""
-
- bl_label = "Colors"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- tex = context.texture
-
- layout.prop(tex, "use_color_ramp", text="Ramp")
- if tex.use_color_ramp:
- layout.template_color_ramp(tex, "color_ramp", expand=True)
-
- split = layout.split()
-
- col = split.column()
- col.label(text="RGB Multiply:")
- sub = col.column(align=True)
- sub.prop(tex, "factor_red", text="R")
- sub.prop(tex, "factor_green", text="G")
- sub.prop(tex, "factor_blue", text="B")
-
- col = split.column()
- col.label(text="Adjust:")
- col.prop(tex, "intensity")
- col.prop(tex, "contrast")
- col.prop(tex, "saturation")
-
- col = layout.column()
- col.prop(tex, "use_clamp", text="Clamp")
-
-
-# Texture Slot Panels #
-
-
-class TEXTURE_OT_POV_texture_slot_add(Operator):
- """Use this class for the add texture slot button."""
-
- bl_idname = "pov.textureslotadd"
- bl_label = "Add"
- bl_description = "Add texture_slot"
- bl_options = {'REGISTER', 'UNDO'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def execute(self, context):
- idblock = pov_context_tex_datablock(context)
- tex = bpy.data.textures.new(name='Texture', type='IMAGE')
- #tex.use_fake_user = True
- #mat = context.view_layer.objects.active.active_material
- slot = idblock.pov_texture_slots.add()
- slot.name = tex.name
- slot.texture = tex.name
- slot.texture_search = tex.name
- # Switch paint brush and paint brush mask
- # to this texture so settings remain contextual
- bpy.context.tool_settings.image_paint.brush.texture = tex
- bpy.context.tool_settings.image_paint.brush.mask_texture = tex
- idblock.pov.active_texture_index = (len(idblock.pov_texture_slots)-1)
-
- #for area in bpy.context.screen.areas:
- #if area.type in ['PROPERTIES']:
- #area.tag_redraw()
-
-
- return {'FINISHED'}
-
-
-class TEXTURE_OT_POV_texture_slot_remove(Operator):
- """Use this class for the remove texture slot button."""
-
- bl_idname = "pov.textureslotremove"
- bl_label = "Remove"
- bl_description = "Remove texture_slot"
- bl_options = {'REGISTER', 'UNDO'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def execute(self, context):
- idblock = pov_context_tex_datablock(context)
- #mat = context.view_layer.objects.active.active_material
- tex_slot = idblock.pov_texture_slots.remove(idblock.pov.active_texture_index)
- if idblock.pov.active_texture_index > 0:
- idblock.pov.active_texture_index -= 1
- try:
- tex = idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
- except IndexError:
- # No more slots
- return {'FINISHED'}
- # Switch paint brush to previous texture so settings remain contextual
- # if 'tex' in locals(): # Would test is the tex variable is assigned / exists
- bpy.context.tool_settings.image_paint.brush.texture = bpy.data.textures[tex]
- bpy.context.tool_settings.image_paint.brush.mask_texture = bpy.data.textures[tex]
-
- return {'FINISHED'}
-
-class TextureSlotPanel(TextureButtonsPanel):
- """Use this class to show pov texture slots panel."""
-
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- if not hasattr(context, "pov_texture_slot"):
- return False
-
- engine = context.scene.render.engine
- return TextureButtonsPanel.poll(cls, context) and (
- engine in cls.COMPAT_ENGINES
- )
-
-
-class TEXTURE_PT_POV_type(TextureButtonsPanel, Panel):
- """Use this class to define pov texture type buttons."""
-
- bl_label = "POV Textures"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- bl_options = {'HIDE_HEADER'}
-
- def draw(self, context):
- layout = self.layout
- world = context.world
- tex = context.texture
-
- split = layout.split(factor=0.2)
- split.label(text="Pattern")
- split.prop(tex.pov, "tex_pattern_type", text="")
-
- # row = layout.row()
- # row.template_list("WORLD_TEXTURE_SLOTS_UL_List", "texture_slots", world,
- # world.texture_slots, world, "active_texture_index")
-
-
-class TEXTURE_PT_POV_preview(TextureButtonsPanel, Panel):
- """Use this class to define pov texture preview panel."""
-
- bl_label = "Preview"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- bl_options = {'HIDE_HEADER'}
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- if not hasattr(context, "pov_texture_slot"):
- return False
- tex = context.texture
- mat = bpy.context.active_object.active_material
- return (
- tex
- and (tex.pov.tex_pattern_type != 'emulator')
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- tex = context.texture
- slot = getattr(context, "pov_texture_slot", None)
- idblock = pov_context_tex_datablock(context)
- layout = self.layout
- # if idblock:
- # layout.template_preview(tex, parent=idblock, slot=slot)
- if tex.pov.tex_pattern_type != 'emulator':
- layout.operator("tex.preview_update")
- else:
- layout.template_preview(tex, slot=slot)
-
-
-class TEXTURE_PT_POV_parameters(TextureButtonsPanel, Panel):
- """Use this class to define pov texture pattern buttons."""
-
- bl_label = "POV Pattern Options"
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw(self, context):
- mat = bpy.context.active_object.active_material
- layout = self.layout
- tex = context.texture
- align = True
- if tex is not None and tex.pov.tex_pattern_type != 'emulator':
- if tex.pov.tex_pattern_type == 'agate':
- layout.prop(
- tex.pov, "modifier_turbulence", text="Agate Turbulence"
- )
- if tex.pov.tex_pattern_type in {'spiral1', 'spiral2'}:
- layout.prop(tex.pov, "modifier_numbers", text="Number of arms")
- if tex.pov.tex_pattern_type == 'tiling':
- layout.prop(tex.pov, "modifier_numbers", text="Pattern number")
- if tex.pov.tex_pattern_type == 'magnet':
- layout.prop(tex.pov, "magnet_style", text="Magnet style")
- if tex.pov.tex_pattern_type == 'quilted':
- row = layout.row(align=align)
- row.prop(tex.pov, "modifier_control0", text="Control0")
- row.prop(tex.pov, "modifier_control1", text="Control1")
- if tex.pov.tex_pattern_type == 'brick':
- col = layout.column(align=align)
- row = col.row()
- row.prop(tex.pov, "brick_size_x", text="Brick size X")
- row.prop(tex.pov, "brick_size_y", text="Brick size Y")
- row = col.row()
- row.prop(tex.pov, "brick_size_z", text="Brick size Z")
- row.prop(tex.pov, "brick_mortar", text="Brick mortar")
- if tex.pov.tex_pattern_type in {'julia', 'mandel', 'magnet'}:
- col = layout.column(align=align)
- if tex.pov.tex_pattern_type == 'julia':
- row = col.row()
- row.prop(tex.pov, "julia_complex_1", text="Complex 1")
- row.prop(tex.pov, "julia_complex_2", text="Complex 2")
- if (
- tex.pov.tex_pattern_type == 'magnet'
- and tex.pov.magnet_style == 'julia'
- ):
- row = col.row()
- row.prop(tex.pov, "julia_complex_1", text="Complex 1")
- row.prop(tex.pov, "julia_complex_2", text="Complex 2")
- row = col.row()
- if tex.pov.tex_pattern_type in {'julia', 'mandel'}:
- row.prop(tex.pov, "f_exponent", text="Exponent")
- if tex.pov.tex_pattern_type == 'magnet':
- row.prop(tex.pov, "magnet_type", text="Type")
- row.prop(tex.pov, "f_iter", text="Iterations")
- row = col.row()
- row.prop(tex.pov, "f_ior", text="Interior")
- row.prop(tex.pov, "f_ior_fac", text="Factor I")
- row = col.row()
- row.prop(tex.pov, "f_eor", text="Exterior")
- row.prop(tex.pov, "f_eor_fac", text="Factor E")
- if tex.pov.tex_pattern_type == 'gradient':
- layout.label(text="Gradient orientation:")
- column_flow = layout.column_flow(columns=3, align=True)
- column_flow.prop(tex.pov, "grad_orient_x", text="X")
- column_flow.prop(tex.pov, "grad_orient_y", text="Y")
- column_flow.prop(tex.pov, "grad_orient_z", text="Z")
- if tex.pov.tex_pattern_type == 'pavement':
- layout.prop(
- tex.pov, "pave_sides", text="Pavement:number of sides"
- )
- col = layout.column(align=align)
- column_flow = col.column_flow(columns=3, align=True)
- column_flow.prop(tex.pov, "pave_tiles", text="Tiles")
- if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 6:
- column_flow.prop(tex.pov, "pave_pat_35", text="Pattern")
- if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 5:
- column_flow.prop(tex.pov, "pave_pat_22", text="Pattern")
- if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 5:
- column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
- if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 6:
- column_flow.prop(tex.pov, "pave_pat_12", text="Pattern")
- if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 4:
- column_flow.prop(tex.pov, "pave_pat_7", text="Pattern")
- if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 4:
- column_flow.prop(tex.pov, "pave_pat_5", text="Pattern")
- if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 5:
- column_flow.prop(tex.pov, "pave_pat_4", text="Pattern")
- if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 3:
- column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
- if tex.pov.pave_sides == '3' and tex.pov.pave_tiles == 4:
- column_flow.prop(tex.pov, "pave_pat_3", text="Pattern")
- if tex.pov.pave_sides == '4' and tex.pov.pave_tiles == 3:
- column_flow.prop(tex.pov, "pave_pat_2", text="Pattern")
- if tex.pov.pave_sides == '6' and tex.pov.pave_tiles == 6:
- column_flow.label(text="!!! 5 tiles!")
- column_flow.prop(tex.pov, "pave_form", text="Form")
- if tex.pov.tex_pattern_type == 'function':
- layout.prop(tex.pov, "func_list", text="Functions")
- if (
- tex.pov.tex_pattern_type == 'function'
- and tex.pov.func_list != "NONE"
- ):
- func = None
- if tex.pov.func_list in {"f_noise3d", "f_ph", "f_r", "f_th"}:
- func = 0
- if tex.pov.func_list in {
- "f_comma",
- "f_crossed_trough",
- "f_cubic_saddle",
- "f_cushion",
- "f_devils_curve",
- "f_enneper",
- "f_glob",
- "f_heart",
- "f_hex_x",
- "f_hex_y",
- "f_hunt_surface",
- "f_klein_bottle",
- "f_kummer_surface_v1",
- "f_lemniscate_of_gerono",
- "f_mitre",
- "f_nodal_cubic",
- "f_noise_generator",
- "f_odd",
- "f_paraboloid",
- "f_pillow",
- "f_piriform",
- "f_quantum",
- "f_quartic_paraboloid",
- "f_quartic_saddle",
- "f_sphere",
- "f_steiners_roman",
- "f_torus_gumdrop",
- "f_umbrella",
- }:
- func = 1
- if tex.pov.func_list in {
- "f_bicorn",
- "f_bifolia",
- "f_boy_surface",
- "f_superellipsoid",
- "f_torus",
- }:
- func = 2
- if tex.pov.func_list in {
- "f_ellipsoid",
- "f_folium_surface",
- "f_hyperbolic_torus",
- "f_kampyle_of_eudoxus",
- "f_parabolic_torus",
- "f_quartic_cylinder",
- "f_torus2",
- }:
- func = 3
- if tex.pov.func_list in {
- "f_blob2",
- "f_cross_ellipsoids",
- "f_flange_cover",
- "f_isect_ellipsoids",
- "f_kummer_surface_v2",
- "f_ovals_of_cassini",
- "f_rounded_box",
- "f_spikes_2d",
- "f_strophoid",
- }:
- func = 4
- if tex.pov.func_list in {
- "f_algbr_cyl1",
- "f_algbr_cyl2",
- "f_algbr_cyl3",
- "f_algbr_cyl4",
- "f_blob",
- "f_mesh1",
- "f_poly4",
- "f_spikes",
- }:
- func = 5
- if tex.pov.func_list in {
- "f_devils_curve_2d",
- "f_dupin_cyclid",
- "f_folium_surface_2d",
- "f_hetero_mf",
- "f_kampyle_of_eudoxus_2d",
- "f_lemniscate_of_gerono_2d",
- "f_polytubes",
- "f_ridge",
- "f_ridged_mf",
- "f_spiral",
- "f_witch_of_agnesi",
- }:
- func = 6
- if tex.pov.func_list in {
- "f_helix1",
- "f_helix2",
- "f_piriform_2d",
- "f_strophoid_2d",
- }:
- func = 7
- if tex.pov.func_list == "f_helical_torus":
- func = 8
- column_flow = layout.column_flow(columns=3, align=True)
- column_flow.label(text="X")
- column_flow.prop(tex.pov, "func_plus_x", text="")
- column_flow.prop(tex.pov, "func_x", text="Value")
- column_flow = layout.column_flow(columns=3, align=True)
- column_flow.label(text="Y")
- column_flow.prop(tex.pov, "func_plus_y", text="")
- column_flow.prop(tex.pov, "func_y", text="Value")
- column_flow = layout.column_flow(columns=3, align=True)
- column_flow.label(text="Z")
- column_flow.prop(tex.pov, "func_plus_z", text="")
- column_flow.prop(tex.pov, "func_z", text="Value")
- row = layout.row(align=align)
- if func > 0:
- row.prop(tex.pov, "func_P0", text="P0")
- if func > 1:
- row.prop(tex.pov, "func_P1", text="P1")
- row = layout.row(align=align)
- if func > 2:
- row.prop(tex.pov, "func_P2", text="P2")
- if func > 3:
- row.prop(tex.pov, "func_P3", text="P3")
- row = layout.row(align=align)
- if func > 4:
- row.prop(tex.pov, "func_P4", text="P4")
- if func > 5:
- row.prop(tex.pov, "func_P5", text="P5")
- row = layout.row(align=align)
- if func > 6:
- row.prop(tex.pov, "func_P6", text="P6")
- if func > 7:
- row.prop(tex.pov, "func_P7", text="P7")
- row = layout.row(align=align)
- row.prop(tex.pov, "func_P8", text="P8")
- row.prop(tex.pov, "func_P9", text="P9")
- ###################################################End Patterns############################
-
- layout.prop(tex.pov, "warp_types", text="Warp types") # warp
- if tex.pov.warp_types == "TOROIDAL":
- layout.prop(
- tex.pov, "warp_tor_major_radius", text="Major radius"
- )
- if tex.pov.warp_types not in {"CUBIC", "NONE"}:
- layout.prop(
- tex.pov, "warp_orientation", text="Warp orientation"
- )
- col = layout.column(align=align)
- row = col.row()
- row.prop(tex.pov, "warp_dist_exp", text="Distance exponent")
- row = col.row()
- row.prop(tex.pov, "modifier_frequency", text="Frequency")
- row.prop(tex.pov, "modifier_phase", text="Phase")
-
- row = layout.row()
-
- row.label(text="Offset:")
- row.label(text="Scale:")
- row.label(text="Rotate:")
- col = layout.column(align=align)
- row = col.row()
- row.prop(tex.pov, "tex_mov_x", text="X")
- row.prop(tex.pov, "tex_scale_x", text="X")
- row.prop(tex.pov, "tex_rot_x", text="X")
- row = col.row()
- row.prop(tex.pov, "tex_mov_y", text="Y")
- row.prop(tex.pov, "tex_scale_y", text="Y")
- row.prop(tex.pov, "tex_rot_y", text="Y")
- row = col.row()
- row.prop(tex.pov, "tex_mov_z", text="Z")
- row.prop(tex.pov, "tex_scale_z", text="Z")
- row.prop(tex.pov, "tex_rot_z", text="Z")
- row = layout.row()
-
- row.label(text="Turbulence:")
- col = layout.column(align=align)
- row = col.row()
- row.prop(tex.pov, "warp_turbulence_x", text="X")
- row.prop(tex.pov, "modifier_octaves", text="Octaves")
- row = col.row()
- row.prop(tex.pov, "warp_turbulence_y", text="Y")
- row.prop(tex.pov, "modifier_lambda", text="Lambda")
- row = col.row()
- row.prop(tex.pov, "warp_turbulence_z", text="Z")
- row.prop(tex.pov, "modifier_omega", text="Omega")
-
-class TEXTURE_PT_POV_mapping(TextureSlotPanel, Panel):
- """Use this class to define POV texture mapping buttons"""
- bl_label = "Mapping"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
-
- @classmethod
- def poll(cls, context):
- idblock = pov_context_tex_datablock(context)
- if isinstance(idblock, Brush) and not context.sculpt_object:
- return False
-
- if not getattr(context, "texture_slot", None):
- return False
-
- engine = context.scene.render.engine
- return (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- idblock = pov_context_tex_datablock(context)
-
- #tex = context.texture_slot
- tex = mat.pov_texture_slots[
- mat.active_texture_index
- ]
- if not isinstance(idblock, Brush):
- split = layout.split(percentage=0.3)
- col = split.column()
- col.label(text="Coordinates:")
- col = split.column()
- col.prop(tex, "texture_coords", text="")
-
- if tex.texture_coords == 'ORCO':
- """
- ob = context.object
- if ob and ob.type == 'MESH':
- split = layout.split(percentage=0.3)
- split.label(text="Mesh:")
- split.prop(ob.data, "texco_mesh", text="")
- """
- elif tex.texture_coords == 'UV':
- split = layout.split(percentage=0.3)
- split.label(text="Map:")
- ob = context.object
- if ob and ob.type == 'MESH':
- split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="")
- else:
- split.prop(tex, "uv_layer", text="")
-
- elif tex.texture_coords == 'OBJECT':
- split = layout.split(percentage=0.3)
- split.label(text="Object:")
- split.prop(tex, "object", text="")
-
- elif tex.texture_coords == 'ALONG_STROKE':
- split = layout.split(percentage=0.3)
- split.label(text="Use Tips:")
- split.prop(tex, "use_tips", text="")
-
- if isinstance(idblock, Brush):
- if context.sculpt_object or context.image_paint_object:
- brush_texture_settings(layout, idblock, context.sculpt_object)
- else:
- if isinstance(idblock, FreestyleLineStyle):
- split = layout.split(percentage=0.3)
- split.label(text="Projection:")
- split.prop(tex, "mapping", text="")
-
- split = layout.split(percentage=0.3)
- split.separator()
- row = split.row()
- row.prop(tex, "mapping_x", text="")
- row.prop(tex, "mapping_y", text="")
- row.prop(tex, "mapping_z", text="")
-
- elif isinstance(idblock, Material):
- split = layout.split(percentage=0.3)
- split.label(text="Projection:")
- split.prop(tex, "mapping", text="")
-
- split = layout.split()
-
- col = split.column()
- if tex.texture_coords in {'ORCO', 'UV'}:
- col.prop(tex, "use_from_dupli")
- if (idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO'):
- col.prop(tex, "use_map_to_bounds")
- elif tex.texture_coords == 'OBJECT':
- col.prop(tex, "use_from_original")
- if (idblock.type == 'VOLUME'):
- col.prop(tex, "use_map_to_bounds")
- else:
- col.label()
-
- col = split.column()
- row = col.row()
- row.prop(tex, "mapping_x", text="")
- row.prop(tex, "mapping_y", text="")
- row.prop(tex, "mapping_z", text="")
-
- row = layout.row()
- row.column().prop(tex, "offset")
- row.column().prop(tex, "scale")
-
-class TEXTURE_PT_POV_influence(TextureSlotPanel, Panel):
- """Use this class to define pov texture influence buttons."""
-
- bl_label = "Influence"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- #bl_context = 'texture'
- @classmethod
- def poll(cls, context):
- idblock = pov_context_tex_datablock(context)
- if (
- # isinstance(idblock, Brush) and # Brush used for everything since 2.8
- context.scene.texture_context == 'OTHER'
- ): # XXX replace by isinstance(idblock, bpy.types.Brush) and ...
- return False
-
- # Specify below also for pov_world_texture_slots, lights etc.
- # to display for various types of slots but only when any
- if not getattr(idblock, "pov_texture_slots", None):
- return False
-
- engine = context.scene.render.engine
- return engine in cls.COMPAT_ENGINES
-
- def draw(self, context):
-
- layout = self.layout
-
- idblock = pov_context_tex_datablock(context)
- # tex = context.pov_texture_slot
- #mat = bpy.context.active_object.active_material
- texslot = idblock.pov_texture_slots[
- idblock.pov.active_texture_index
- ] # bpy.data.textures[mat.active_texture_index]
- tex = bpy.data.textures[
- idblock.pov_texture_slots[idblock.pov.active_texture_index].texture
- ]
-
- def factor_but(layout, toggle, factor, name):
- row = layout.row(align=True)
- row.prop(texslot, toggle, text="")
- sub = row.row(align=True)
- sub.active = getattr(texslot, toggle)
- sub.prop(texslot, factor, text=name, slider=True)
- return sub # XXX, temp. use_map_normal needs to override.
-
- if isinstance(idblock, Material):
- split = layout.split()
-
- col = split.column()
- if idblock.pov.type in {'SURFACE', 'WIRE'}:
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Diffuse:")
- factor_but(
- col, "use_map_diffuse", "diffuse_factor", "Intensity"
- )
- factor_but(
- col,
- "use_map_color_diffuse",
- "diffuse_color_factor",
- "Color",
- )
- factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
- factor_but(
- col,
- "use_map_translucency",
- "translucency_factor",
- "Translucency",
- )
-
- col.label(text="Specular:")
- factor_but(
- col, "use_map_specular", "specular_factor", "Intensity"
- )
- factor_but(
- col, "use_map_color_spec", "specular_color_factor", "Color"
- )
- factor_but(
- col, "use_map_hardness", "hardness_factor", "Hardness"
- )
-
- col = split.column()
- col.label(text="Shading:")
- factor_but(col, "use_map_ambient", "ambient_factor", "Ambient")
- factor_but(col, "use_map_emit", "emit_factor", "Emit")
- factor_but(col, "use_map_mirror", "mirror_factor", "Mirror")
- factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror")
-
- col.label(text="Geometry:")
- # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
- sub_tmp = factor_but(
- col, "use_map_normal", "normal_factor", "Normal"
- )
- sub_tmp.active = (
- texslot.use_map_normal or texslot.use_map_displacement
- )
- # END XXX
-
- factor_but(col, "use_map_warp", "warp_factor", "Warp")
- factor_but(
- col,
- "use_map_displacement",
- "displacement_factor",
- "Displace",
- )
-
- # ~ sub = col.column()
- # ~ sub.active = texslot.use_map_translucency or texslot.map_emit or texslot.map_alpha or texslot.map_raymir or texslot.map_hardness or texslot.map_ambient or texslot.map_specularity or texslot.map_reflection or texslot.map_mirror
- # ~ sub.prop(texslot, "default_value", text="Amount", slider=True)
- elif idblock.pov.type == 'HALO':
- layout.label(text="Halo:")
-
- split = layout.split()
-
- col = split.column()
- factor_but(
- col,
- "use_map_color_diffuse",
- "diffuse_color_factor",
- "Color",
- )
- factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
-
- col = split.column()
- factor_but(col, "use_map_raymir", "raymir_factor", "Size")
- factor_but(
- col, "use_map_hardness", "hardness_factor", "Hardness"
- )
- factor_but(
- col, "use_map_translucency", "translucency_factor", "Add"
- )
- elif idblock.pov.type == 'VOLUME':
- layout.label(text="Volume:")
-
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_density", "density_factor", "Density")
- factor_but(
- col, "use_map_emission", "emission_factor", "Emission"
- )
- factor_but(
- col, "use_map_scatter", "scattering_factor", "Scattering"
- )
- factor_but(
- col, "use_map_reflect", "reflection_factor", "Reflection"
- )
-
- col = split.column()
- col.label(text=" ")
- factor_but(
- col,
- "use_map_color_emission",
- "emission_color_factor",
- "Emission Color",
- )
- factor_but(
- col,
- "use_map_color_transmission",
- "transmission_color_factor",
- "Transmission Color",
- )
- factor_but(
- col,
- "use_map_color_reflection",
- "reflection_color_factor",
- "Reflection Color",
- )
-
- layout.label(text="Geometry:")
-
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_warp", "warp_factor", "Warp")
-
- col = split.column()
- factor_but(
- col,
- "use_map_displacement",
- "displacement_factor",
- "Displace",
- )
-
- elif isinstance(idblock, Light):
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_color", "color_factor", "Color")
-
- col = split.column()
- factor_but(col, "use_map_shadow", "shadow_factor", "Shadow")
-
- elif isinstance(idblock, World):
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_blend", "blend_factor", "Blend")
- factor_but(col, "use_map_horizon", "horizon_factor", "Horizon")
-
- col = split.column()
- factor_but(
- col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up"
- )
- factor_but(
- col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down"
- )
- elif isinstance(idblock, ParticleSettings):
- split = layout.split()
-
- col = split.column()
- col.label(text="General:")
- factor_but(col, "use_map_time", "time_factor", "Time")
- factor_but(col, "use_map_life", "life_factor", "Lifetime")
- factor_but(col, "use_map_density", "density_factor", "Density")
- factor_but(col, "use_map_size", "size_factor", "Size")
-
- col = split.column()
- col.label(text="Physics:")
- factor_but(col, "use_map_velocity", "velocity_factor", "Velocity")
- factor_but(col, "use_map_damp", "damp_factor", "Damp")
- factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
- factor_but(col, "use_map_field", "field_factor", "Force Fields")
-
- layout.label(text="Hair:")
-
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_length", "length_factor", "Length")
- factor_but(col, "use_map_clump", "clump_factor", "Clump")
- factor_but(col, "use_map_twist", "twist_factor", "Twist")
-
- col = split.column()
- factor_but(
- col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude"
- )
- factor_but(
- col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency"
- )
- factor_but(col, "use_map_rough", "rough_factor", "Rough")
-
- elif isinstance(idblock, FreestyleLineStyle):
- split = layout.split()
-
- col = split.column()
- factor_but(
- col, "use_map_color_diffuse", "diffuse_color_factor", "Color"
- )
- col = split.column()
- factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
-
- layout.separator()
-
- if not isinstance(idblock, ParticleSettings):
- split = layout.split()
-
- col = split.column()
- # col.prop(tex, "blend_type", text="Blend") #deprecated since 2.8
- # col.prop(tex, "use_rgb_to_intensity") #deprecated since 2.8
- # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
- # col.prop(tex, "color", text="") #deprecated since 2.8
-
- col = split.column()
- # col.prop(tex, "invert", text="Negative") #deprecated since 2.8
- # col.prop(tex, "use_stencil") #deprecated since 2.8
-
- # if isinstance(idblock, (Material, World)):
- # col.prop(tex, "default_value", text="DVar", slider=True)
-
-
-class TEXTURE_PT_POV_tex_gamma(TextureButtonsPanel, Panel):
- """Use this class to define pov texture gamma buttons."""
-
- bl_label = "Image Gamma"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw_header(self, context):
- tex = context.texture
-
- self.layout.prop(
- tex.pov, "tex_gamma_enable", text="", icon='SEQ_LUMA_WAVEFORM'
- )
-
- def draw(self, context):
- layout = self.layout
-
- tex = context.texture
-
- layout.active = tex.pov.tex_gamma_enable
- layout.prop(tex.pov, "tex_gamma_value", text="Gamma Value")
-
-
-# commented out below UI for texture only custom code inside exported material:
-# class TEXTURE_PT_povray_replacement_text(TextureButtonsPanel, Panel):
-# bl_label = "Custom POV Code"
-# COMPAT_ENGINES = {'POVRAY_RENDER'}
-
-# def draw(self, context):
-# layout = self.layout
-
-# tex = context.texture
-
-# col = layout.column()
-# col.label(text="Replace properties with:")
-# col.prop(tex.pov, "replacement_text", text="")
-
-
-class OBJECT_PT_POV_obj_parameters(ObjectButtonsPanel, Panel):
- """Use this class to define pov specific object level options buttons."""
-
- bl_label = "POV"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
-
- engine = context.scene.render.engine
- return engine in cls.COMPAT_ENGINES
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- split = layout.split()
-
- col = split.column(align=True)
-
- col.label(text="Radiosity:")
- col.prop(obj.pov, "importance_value", text="Importance")
- col.label(text="Photons:")
- col.prop(obj.pov, "collect_photons", text="Receive Photon Caustics")
- if obj.pov.collect_photons:
- col.prop(
- obj.pov, "spacing_multiplier", text="Photons Spacing Multiplier"
- )
-
- split = layout.split()
-
- col = split.column()
- col.prop(obj.pov, "hollow")
- col.prop(obj.pov, "double_illuminate")
-
- if obj.type == 'META' or obj.pov.curveshape == 'lathe':
- # if obj.pov.curveshape == 'sor'
- col.prop(obj.pov, "sturm")
- col.prop(obj.pov, "no_shadow")
- col.prop(obj.pov, "no_image")
- col.prop(obj.pov, "no_reflection")
- col.prop(obj.pov, "no_radiosity")
- col.prop(obj.pov, "inverse")
- col.prop(obj.pov, "hierarchy")
- # col.prop(obj.pov,"boundorclip",text="Bound / Clip")
- # if obj.pov.boundorclip != "none":
- # col.prop_search(obj.pov,"boundorclipob",context.blend_data,"objects",text="Object")
- # text = "Clipped by"
- # if obj.pov.boundorclip == "clipped_by":
- # text = "Bounded by"
- # col.prop(obj.pov,"addboundorclip",text=text)
-
-
-class OBJECT_PT_POV_obj_sphere(PovDataButtonsPanel, Panel):
- """Use this class to define pov sphere primitive parameters buttons."""
-
- bl_label = "POV Sphere"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- # bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- return (
- obj
- and obj.pov.object_as == 'SPHERE'
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- col = layout.column()
-
- if obj.pov.object_as == 'SPHERE':
- if obj.pov.unlock_parameters == False:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Exported parameters below",
- icon='LOCKED',
- )
- col.label(text="Sphere radius: " + str(obj.pov.sphere_radius))
-
- else:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Edit exported parameters",
- icon='UNLOCKED',
- )
- col.label(text="3D view proxy may get out of synch")
- col.active = obj.pov.unlock_parameters
-
- layout.operator(
- "pov.sphere_update", text="Update", icon="SHADING_RENDERED"
- )
-
- # col.label(text="Parameters:")
- col.prop(obj.pov, "sphere_radius", text="Radius of Sphere")
-
-
-class OBJECT_PT_POV_obj_cylinder(PovDataButtonsPanel, Panel):
- """Use this class to define pov cylinder primitive parameters buttons."""
-
- bl_label = "POV Cylinder"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- # bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- return (
- obj
- and obj.pov.object_as == 'CYLINDER'
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- col = layout.column()
-
- if obj.pov.object_as == 'CYLINDER':
- if obj.pov.unlock_parameters == False:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Exported parameters below",
- icon='LOCKED',
- )
- col.label(
- text="Cylinder radius: " + str(obj.pov.cylinder_radius)
- )
- col.label(
- text="Cylinder cap location: "
- + str(obj.pov.cylinder_location_cap)
- )
-
- else:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Edit exported parameters",
- icon='UNLOCKED',
- )
- col.label(text="3D view proxy may get out of synch")
- col.active = obj.pov.unlock_parameters
-
- layout.operator(
- "pov.cylinder_update", text="Update", icon="MESH_CYLINDER"
- )
-
- # col.label(text="Parameters:")
- col.prop(obj.pov, "cylinder_radius")
- col.prop(obj.pov, "cylinder_location_cap")
-
-
-class OBJECT_PT_POV_obj_cone(PovDataButtonsPanel, Panel):
- """Use this class to define pov cone primitive parameters buttons."""
-
- bl_label = "POV Cone"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- # bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- return (
- obj
- and obj.pov.object_as == 'CONE'
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- col = layout.column()
-
- if obj.pov.object_as == 'CONE':
- if obj.pov.unlock_parameters == False:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Exported parameters below",
- icon='LOCKED',
- )
- col.label(
- text="Cone base radius: " + str(obj.pov.cone_base_radius)
- )
- col.label(
- text="Cone cap radius: " + str(obj.pov.cone_cap_radius)
- )
- col.label(
- text="Cone proxy segments: " + str(obj.pov.cone_segments)
- )
- col.label(text="Cone height: " + str(obj.pov.cone_height))
- else:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Edit exported parameters",
- icon='UNLOCKED',
- )
- col.label(text="3D view proxy may get out of synch")
- col.active = obj.pov.unlock_parameters
-
- layout.operator(
- "pov.cone_update", text="Update", icon="MESH_CONE"
- )
-
- # col.label(text="Parameters:")
- col.prop(
- obj.pov, "cone_base_radius", text="Radius of Cone Base"
- )
- col.prop(obj.pov, "cone_cap_radius", text="Radius of Cone Cap")
- col.prop(
- obj.pov, "cone_segments", text="Segmentation of Cone proxy"
- )
- col.prop(obj.pov, "cone_height", text="Height of the cone")
-
-
-class OBJECT_PT_POV_obj_superellipsoid(PovDataButtonsPanel, Panel):
- """Use this class to define pov superellipsoid primitive parameters buttons."""
-
- bl_label = "POV Superquadric ellipsoid"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- # bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- return (
- obj
- and obj.pov.object_as == 'SUPERELLIPSOID'
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- col = layout.column()
-
- if obj.pov.object_as == 'SUPERELLIPSOID':
- if obj.pov.unlock_parameters == False:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Exported parameters below",
- icon='LOCKED',
- )
- col.label(text="Radial segmentation: " + str(obj.pov.se_u))
- col.label(text="Lateral segmentation: " + str(obj.pov.se_v))
- col.label(text="Ring shape: " + str(obj.pov.se_n1))
- col.label(text="Cross-section shape: " + str(obj.pov.se_n2))
- col.label(text="Fill up and down: " + str(obj.pov.se_edit))
- else:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Edit exported parameters",
- icon='UNLOCKED',
- )
- col.label(text="3D view proxy may get out of synch")
- col.active = obj.pov.unlock_parameters
-
- layout.operator(
- "pov.superellipsoid_update",
- text="Update",
- icon="MOD_SUBSURF",
- )
-
- # col.label(text="Parameters:")
- col.prop(obj.pov, "se_u")
- col.prop(obj.pov, "se_v")
- col.prop(obj.pov, "se_n1")
- col.prop(obj.pov, "se_n2")
- col.prop(obj.pov, "se_edit")
-
-
-class OBJECT_PT_POV_obj_torus(PovDataButtonsPanel, Panel):
- """Use this class to define pov torus primitive parameters buttons."""
-
- bl_label = "POV Torus"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- # bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- return (
- obj
- and obj.pov.object_as == 'TORUS'
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- col = layout.column()
-
- if obj.pov.object_as == 'TORUS':
- if obj.pov.unlock_parameters == False:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Exported parameters below",
- icon='LOCKED',
- )
- col.label(
- text="Torus major radius: "
- + str(obj.pov.torus_major_radius)
- )
- col.label(
- text="Torus minor radius: "
- + str(obj.pov.torus_minor_radius)
- )
- col.label(
- text="Torus major segments: "
- + str(obj.pov.torus_major_segments)
- )
- col.label(
- text="Torus minor segments: "
- + str(obj.pov.torus_minor_segments)
- )
- else:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Edit exported parameters",
- icon='UNLOCKED',
- )
- col.label(text="3D view proxy may get out of synch")
- col.active = obj.pov.unlock_parameters
-
- layout.operator(
- "pov.torus_update", text="Update", icon="MESH_TORUS"
- )
-
- # col.label(text="Parameters:")
- col.prop(obj.pov, "torus_major_radius")
- col.prop(obj.pov, "torus_minor_radius")
- col.prop(obj.pov, "torus_major_segments")
- col.prop(obj.pov, "torus_minor_segments")
-
-
-class OBJECT_PT_POV_obj_supertorus(PovDataButtonsPanel, Panel):
- """Use this class to define pov supertorus primitive parameters buttons."""
-
- bl_label = "POV SuperTorus"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- # bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- return (
- obj
- and obj.pov.object_as == 'SUPERTORUS'
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- col = layout.column()
-
- if obj.pov.object_as == 'SUPERTORUS':
- if obj.pov.unlock_parameters == False:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Exported parameters below",
- icon='LOCKED',
- )
- col.label(
- text="SuperTorus major radius: "
- + str(obj.pov.st_major_radius)
- )
- col.label(
- text="SuperTorus minor radius: "
- + str(obj.pov.st_minor_radius)
- )
- col.label(
- text="SuperTorus major segments: " + str(obj.pov.st_u)
- )
- col.label(
- text="SuperTorus minor segments: " + str(obj.pov.st_v)
- )
-
- col.label(
- text="SuperTorus Ring Manipulator: " + str(obj.pov.st_ring)
- )
- col.label(
- text="SuperTorus Cross Manipulator: "
- + str(obj.pov.st_cross)
- )
- col.label(
- text="SuperTorus Internal And External radii: "
- + str(obj.pov.st_ie)
- )
-
- col.label(
- text="SuperTorus accuracy: " + str(ob.pov.st_accuracy)
- )
- col.label(
- text="SuperTorus max gradient: "
- + str(ob.pov.st_max_gradient)
- )
-
- else:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Edit exported parameters",
- icon='UNLOCKED',
- )
- col.label(text="3D view proxy may get out of synch")
- col.active = obj.pov.unlock_parameters
-
- layout.operator(
- "pov.supertorus_update", text="Update", icon="MESH_TORUS"
- )
-
- # col.label(text="Parameters:")
- col.prop(obj.pov, "st_major_radius")
- col.prop(obj.pov, "st_minor_radius")
- col.prop(obj.pov, "st_u")
- col.prop(obj.pov, "st_v")
- col.prop(obj.pov, "st_ring")
- col.prop(obj.pov, "st_cross")
- col.prop(obj.pov, "st_ie")
- # col.prop(obj.pov, "st_edit") #?
- col.prop(obj.pov, "st_accuracy")
- col.prop(obj.pov, "st_max_gradient")
-
-
-class OBJECT_PT_POV_obj_parametric(PovDataButtonsPanel, Panel):
- """Use this class to define pov parametric surface primitive parameters buttons."""
-
- bl_label = "POV Parametric surface"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- # bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- obj = context.object
- return (
- obj
- and obj.pov.object_as == 'PARAMETRIC'
- and (engine in cls.COMPAT_ENGINES)
- )
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- col = layout.column()
-
- if obj.pov.object_as == 'PARAMETRIC':
- if obj.pov.unlock_parameters == False:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Exported parameters below",
- icon='LOCKED',
- )
- col.label(text="Minimum U: " + str(obj.pov.u_min))
- col.label(text="Minimum V: " + str(obj.pov.v_min))
- col.label(text="Maximum U: " + str(obj.pov.u_max))
- col.label(text="Minimum V: " + str(obj.pov.v_min))
- col.label(text="X Function: " + str(obj.pov.x_eq))
- col.label(text="Y Function: " + str(obj.pov.y_eq))
- col.label(text="Z Function: " + str(obj.pov.x_eq))
-
- else:
- col.prop(
- obj.pov,
- "unlock_parameters",
- text="Edit exported parameters",
- icon='UNLOCKED',
- )
- col.label(text="3D view proxy may get out of synch")
- col.active = obj.pov.unlock_parameters
-
- layout.operator(
- "pov.parametric_update", text="Update", icon="SCRIPTPLUGINS"
- )
-
- col.prop(obj.pov, "u_min", text="Minimum U")
- col.prop(obj.pov, "v_min", text="Minimum V")
- col.prop(obj.pov, "u_max", text="Maximum U")
- col.prop(obj.pov, "v_max", text="Minimum V")
- col.prop(obj.pov, "x_eq", text="X Function")
- col.prop(obj.pov, "y_eq", text="Y Function")
- col.prop(obj.pov, "z_eq", text="Z Function")
-
-
-class OBJECT_PT_povray_replacement_text(ObjectButtonsPanel, Panel):
- """Use this class to define pov object replacement field."""
-
- bl_label = "Custom POV Code"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- obj = context.object
-
- col = layout.column()
- col.label(text="Replace properties with:")
- col.prop(obj.pov, "replacement_text", text="")
-
-
-###############################################################################
-# Add Povray Objects
-###############################################################################
-
-
-class VIEW_MT_POV_primitives_add(Menu):
- """Define the primitives menu with presets"""
-
- bl_idname = "VIEW_MT_POV_primitives_add"
- bl_label = "Povray"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- return engine == 'POVRAY_RENDER'
-
- def draw(self, context):
- layout = self.layout
- layout.operator_context = 'INVOKE_REGION_WIN'
- layout.menu(
- VIEW_MT_POV_Basic_Shapes.bl_idname, text="Primitives", icon="GROUP"
- )
- layout.menu(VIEW_MT_POV_import.bl_idname, text="Import", icon="IMPORT")
-
-
-class VIEW_MT_POV_Basic_Shapes(Menu):
- """Use this class to sort simple primitives menu entries."""
-
- bl_idname = "POVRAY_MT_basic_shape_tools"
- bl_label = "Basic_shapes"
-
- def draw(self, context):
- layout = self.layout
- layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator(
- "pov.addplane", text="Infinite Plane", icon='MESH_PLANE'
- )
- layout.operator("pov.addbox", text="Box", icon='MESH_CUBE')
- layout.operator("pov.addsphere", text="Sphere", icon='SHADING_RENDERED')
- layout.operator(
- "pov.addcylinder", text="Cylinder", icon="MESH_CYLINDER"
- )
- layout.operator("pov.cone_add", text="Cone", icon="MESH_CONE")
- layout.operator("pov.addtorus", text="Torus", icon='MESH_TORUS')
- layout.separator()
- layout.operator("pov.addrainbow", text="Rainbow", icon="COLOR")
- layout.operator("pov.addlathe", text="Lathe", icon='MOD_SCREW')
- layout.operator("pov.addprism", text="Prism", icon='MOD_SOLIDIFY')
- layout.operator(
- "pov.addsuperellipsoid",
- text="Superquadric Ellipsoid",
- icon='MOD_SUBSURF',
- )
- layout.operator(
- "pov.addheightfield", text="Height Field", icon="RNDCURVE"
- )
- layout.operator(
- "pov.addspheresweep", text="Sphere Sweep", icon='FORCE_CURVE'
- )
- layout.separator()
- layout.operator(
- "pov.addblobsphere", text="Blob Sphere", icon='META_DATA'
- )
- layout.separator()
- layout.label(text="Isosurfaces")
- layout.operator(
- "pov.addisosurfacebox", text="Isosurface Box", icon="META_CUBE"
- )
- layout.operator(
- "pov.addisosurfacesphere",
- text="Isosurface Sphere",
- icon="META_BALL",
- )
- layout.operator(
- "pov.addsupertorus", text="Supertorus", icon="SURFACE_NTORUS"
- )
- layout.separator()
- layout.label(text="Macro based")
- layout.operator(
- "pov.addpolygontocircle",
- text="Polygon To Circle Blending",
- icon="MOD_CAST",
- )
- layout.operator("pov.addloft", text="Loft", icon="SURFACE_NSURFACE")
- layout.separator()
- # Warning if the Add Advanced Objects addon containing
- # Add mesh extra objects is not enabled
- if not check_add_mesh_extra_objects():
- # col = box.column()
- layout.label(
- text="Please enable Add Mesh: Extra Objects addon", icon="INFO"
- )
- # layout.separator()
- layout.operator(
- "preferences.addon_show",
- text="Go to Add Mesh: Extra Objects addon",
- icon="PREFERENCES",
- ).module = "add_mesh_extra_objects"
-
- # layout.separator()
- return
- else:
- layout.operator(
- "pov.addparametric", text="Parametric", icon='SCRIPTPLUGINS'
- )
-
-
-class VIEW_MT_POV_import(Menu):
- """Use this class for the import menu."""
-
- bl_idname = "POVRAY_MT_import_tools"
- bl_label = "Import"
-
- def draw(self, context):
- layout = self.layout
- layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
-
-
-def menu_func_add(self, context):
- engine = context.scene.render.engine
- if engine == 'POVRAY_RENDER':
- self.layout.menu("VIEW_MT_POV_primitives_add", icon="PLUGIN")
-
-
-def menu_func_import(self, context):
- engine = context.scene.render.engine
- if engine == 'POVRAY_RENDER':
- self.layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
-
-
-##############Nodes
-
-# def find_node_input(node, name):
-# for input in node.inputs:
-# if input.name == name:
-# return input
-
-# def panel_node_draw(layout, id_data, output_type, input_name):
-# if not id_data.use_nodes:
-# #layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
-# #layout.operator("pov.use_shading_nodes", icon='NODETREE')
-# layout.operator("WM_OT_context_toggle", icon='NODETREE').data_path = \
-# "material.pov.material_use_nodes"
-# return False
-
-# ntree = id_data.node_tree
-
-# node = find_node(id_data, output_type)
-# if not node:
-# layout.label(text="No output node")
-# else:
-# input = find_node_input(node, input_name)
-# layout.template_node_view(ntree, node, input)
-
-# return True
-
-
-class NODE_MT_POV_map_create(Menu):
- """Create maps"""
-
- bl_idname = "POVRAY_MT_node_map_create"
- bl_label = "Create map"
-
- def draw(self, context):
- layout = self.layout
- layout.operator("node.map_create")
-
-
-def menu_func_nodes(self, context):
- ob = context.object
- if hasattr(ob, 'active_material'):
- mat = context.object.active_material
- if mat and context.space_data.tree_type == 'ObjectNodeTree':
- self.layout.prop(mat.pov, "material_use_nodes")
- self.layout.menu(NODE_MT_POV_map_create.bl_idname)
- self.layout.operator("wm.updatepreviewkey")
- if (
- hasattr(mat, 'active_texture')
- and context.scene.render.engine == 'POVRAY_RENDER'
- ):
- tex = mat.active_texture
- if tex and context.space_data.tree_type == 'TextureNodeTree':
- self.layout.prop(tex.pov, "texture_use_nodes")
-
-
-###############################################################################
-# Camera Povray Settings
-###############################################################################
-class CAMERA_PT_POV_cam_dof(CameraDataButtonsPanel, Panel):
- """Use this class for camera depth of field focal blur buttons."""
-
- bl_label = "POV Aperture"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
- bl_parent_id = "DATA_PT_camera_dof_aperture"
- bl_options = {'HIDE_HEADER'}
- # def draw_header(self, context):
- # cam = context.camera
-
- # self.layout.prop(cam.pov, "dof_enable", text="")
-
- def draw(self, context):
- layout = self.layout
-
- cam = context.camera
-
- layout.active = cam.dof.use_dof
- layout.use_property_split = True # Active single-column layout
-
- flow = layout.grid_flow(
- row_major=True,
- columns=0,
- even_columns=True,
- even_rows=False,
- align=False,
- )
-
- col = flow.column()
- col.label(text="F-Stop value will export as")
- col.label(
- text="POV aperture : "
- + "%.3f" % (1 / cam.dof.aperture_fstop * 1000)
- )
-
- col = flow.column()
- col.prop(cam.pov, "dof_samples_min")
- col.prop(cam.pov, "dof_samples_max")
- col.prop(cam.pov, "dof_variance")
- col.prop(cam.pov, "dof_confidence")
-
-
-class CAMERA_PT_POV_cam_nor(CameraDataButtonsPanel, Panel):
- """Use this class for camera normal perturbation buttons."""
-
- bl_label = "POV Perturbation"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw_header(self, context):
- cam = context.camera
-
- self.layout.prop(cam.pov, "normal_enable", text="")
-
- def draw(self, context):
- layout = self.layout
-
- cam = context.camera
-
- layout.active = cam.pov.normal_enable
-
- layout.prop(cam.pov, "normal_patterns")
- layout.prop(cam.pov, "cam_normal")
- layout.prop(cam.pov, "turbulence")
- layout.prop(cam.pov, "scale")
-
-
-class CAMERA_PT_POV_replacement_text(CameraDataButtonsPanel, Panel):
- """Use this class for camera text replacement field."""
-
- bl_label = "Custom POV Code"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- cam = context.camera
-
- col = layout.column()
- col.label(text="Replace properties with:")
- col.prop(cam.pov, "replacement_text", text="")
-
-
-###############################################################################
-# Text Povray Settings
-###############################################################################
-
-
-class TEXT_OT_POV_insert(Operator):
- """Use this class to create blender text editor operator to insert pov snippets like other pov IDEs"""
-
- bl_idname = "text.povray_insert"
- bl_label = "Insert"
-
- filepath: bpy.props.StringProperty(name="Filepath", subtype='FILE_PATH')
-
- @classmethod
- def poll(cls, context):
- # context.area.type == 'TEXT_EDITOR'
- return bpy.ops.text.insert.poll()
-
- def execute(self, context):
- if self.filepath and isfile(self.filepath):
- file = open(self.filepath, "r")
- bpy.ops.text.insert(text=file.read())
-
- # places the cursor at the end without scrolling -.-
- # context.space_data.text.write(file.read())
- file.close()
- return {'FINISHED'}
-
-
-def validinsert(ext):
- return ext in {".txt", ".inc", ".pov"}
-
-
-class TEXT_MT_POV_insert(Menu):
- """Use this class to create a menu launcher in text editor for the TEXT_OT_POV_insert operator ."""
-
- bl_label = "Insert"
- bl_idname = "TEXT_MT_POV_insert"
-
- def draw(self, context):
- pov_documents = locate_docpath()
- prop = self.layout.operator(
- "wm.path_open", text="Open folder", icon='FILE_FOLDER'
- )
- prop.filepath = pov_documents
- self.layout.separator()
-
- list = []
- for root, dirs, files in os.walk(pov_documents):
- list.append(root)
- print(list)
- self.path_menu(
- list,
- "text.povray_insert",
- # {"internal": True},
- filter_ext=validinsert,
- )
-
-
-class TEXT_PT_POV_custom_code(TextButtonsPanel, Panel):
- """Use this class to create a panel in text editor for the user to decide if he renders text only or adds to 3d scene."""
-
- bl_label = "POV"
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- text = context.space_data.text
-
- pov_documents = locate_docpath()
- if not pov_documents:
- layout.label(text="Please configure ", icon="INFO")
- layout.label(text="default pov include path ")
- layout.label(text="in addon preferences")
- # layout.separator()
- layout.operator(
- "preferences.addon_show",
- text="Go to Render: Persistence of Vision addon",
- icon="PREFERENCES",
- ).module = "render_povray"
-
- # layout.separator()
- else:
- # print(pov_documents)
- layout.menu(TEXT_MT_POV_insert.bl_idname)
-
- if text:
- box = layout.box()
- box.label(text='Source to render:', icon='RENDER_STILL')
- row = box.row()
- row.prop(text.pov, "custom_code", expand=True)
- if text.pov.custom_code in {'3dview'}:
- box.operator("render.render", icon='OUTLINER_DATA_ARMATURE')
- if text.pov.custom_code in {'text'}:
- rtext = bpy.context.space_data.text
- box.operator("text.run", icon='ARMATURE_DATA')
- # layout.prop(text.pov, "custom_code")
- elif text.pov.custom_code in {'both'}:
- box.operator("render.render", icon='POSE_HLT')
- layout.label(text="Please specify declared", icon="INFO")
- layout.label(text="items in properties ")
- # layout.label(text="")
- layout.label(text="replacement fields")
-
-
-###############################################
-# Text editor templates from header menu
-
-
-class TEXT_MT_POV_templates(Menu):
- """Use this class to create a menu for the same pov templates scenes as other pov IDEs."""
-
- bl_label = "POV"
-
- # We list templates on file evaluation, we can assume they are static data,
- # and better avoid running this on every draw call.
- import os
-
- template_paths = [os.path.join(os.path.dirname(__file__), "templates_pov")]
-
- def draw(self, context):
- self.path_menu(
- self.template_paths, "text.open", props_default={"internal": True}
- )
-
-
-def menu_func_templates(self, context):
- # Do not depend on POV being active renderer here...
- self.layout.menu("TEXT_MT_POV_templates")
-
-###############################################################################
-# Freestyle
-###############################################################################
-#import addon_utils
-#addon_utils.paths()[0]
-#addon_utils.modules()
-#mod.bl_info['name'] == 'Freestyle SVG Exporter':
-bpy.utils.script_paths("addons")
-#render_freestyle_svg = os.path.join(bpy.utils.script_paths("addons"), "render_freestyle_svg.py")
-
-render_freestyle_svg = bpy.context.preferences.addons.get('render_freestyle_svg')
- #mpath=addon_utils.paths()[0].render_freestyle_svg
- #import mpath
- #from mpath import render_freestyle_svg #= addon_utils.modules(['Freestyle SVG Exporter'])
- #from scripts\\addons import render_freestyle_svg
-if check_render_freestyle_svg():
- '''
- snippetsWIP
- import myscript
- import importlib
-
- importlib.reload(myscript)
- myscript.main()
- '''
- for member in dir(render_freestyle_svg):
- subclass = getattr(render_freestyle_svg, member)
- try:
- subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
- if subclass.bl_idname == "RENDER_PT_SVGExporterPanel":
- subclass.bl_parent_id = "RENDER_PT_POV_filter"
- subclass.bl_options = {'HIDE_HEADER'}
- #subclass.bl_order = 11
- print(subclass.bl_info)
- except:
- pass
-
- #del render_freestyle_svg.RENDER_PT_SVGExporterPanel.bl_parent_id
-
-
-class RENDER_PT_POV_filter(RenderButtonsPanel, Panel):
- """Use this class to invoke stuff like Freestyle UI."""
-
- bl_label = "Freestyle"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'POVRAY_RENDER'}
-
- @classmethod
- def poll(cls, context):
- with_freestyle = bpy.app.build_options.freestyle
- engine = context.scene.render.engine
- return(with_freestyle and engine == 'POVRAY_RENDER')
- def draw_header(self, context):
-
- #scene = context.scene
- rd = context.scene.render
- layout = self.layout
-
- if rd.use_freestyle:
- layout.prop(
- rd, "use_freestyle", text="", icon='LINE_DATA'
- )
-
- else:
- layout.prop(
- rd, "use_freestyle", text="", icon='OUTLINER_OB_IMAGE'
- )
-
- def draw(self, context):
- rd = context.scene.render
- layout = self.layout
- layout.active = rd.use_freestyle
- layout.use_property_split = True
- layout.use_property_decorate = False # No animation.
- flow = layout.grid_flow(
- row_major=True,
- columns=0,
- even_columns=True,
- even_rows=False,
- align=True,
- )
-
- flow.prop(rd, "line_thickness_mode", expand=True)
-
- if rd.line_thickness_mode == 'ABSOLUTE':
- flow.prop(rd, "line_thickness")
-
- # Warning if the Freestyle SVG Exporter addon is not enabled
- if not check_render_freestyle_svg():
- # col = box.column()
- layout.label(
- text="Please enable Freestyle SVG Exporter addon", icon="INFO"
- )
- # layout.separator()
- layout.operator(
- "preferences.addon_show",
- text="Go to Render: Freestyle SVG Exporter addon",
- icon="PREFERENCES",
- ).module = "render_freestyle_svg"
-
-classes = (
- WORLD_PT_POV_world,
- WORLD_MT_POV_presets,
- WORLD_OT_POV_add_preset,
- WORLD_TEXTURE_SLOTS_UL_POV_layerlist,
- #WORLD_TEXTURE_SLOTS_UL_List,
- WORLD_PT_POV_mist,
- # RenderButtonsPanel,
- # ModifierButtonsPanel,
- # MaterialButtonsPanel,
- # TextureButtonsPanel,
- # ObjectButtonsPanel,
- # CameraDataButtonsPanel,
- # WorldButtonsPanel,
- # TextButtonsPanel,
- # PovDataButtonsPanel,
- DATA_PT_POV_normals,
- DATA_PT_POV_texture_space,
- DATA_PT_POV_vertex_groups,
- DATA_PT_POV_shape_keys,
- DATA_PT_POV_uv_texture,
- DATA_PT_POV_vertex_colors,
- DATA_PT_POV_customdata,
- # PovLampButtonsPanel,
- LIGHT_PT_POV_preview,
- LIGHT_PT_POV_light,
- LIGHT_MT_POV_presets,
- LIGHT_OT_POV_add_preset,
- OBJECT_PT_POV_rainbow,
- RENDER_PT_POV_export_settings,
- RENDER_PT_POV_render_settings,
- RENDER_PT_POV_photons,
- RENDER_PT_POV_antialias,
- RENDER_PT_POV_radiosity,
- RENDER_PT_POV_filter,
- POV_RADIOSITY_MT_presets,
- RENDER_OT_POV_radiosity_add_preset,
- RENDER_PT_POV_media,
- MODIFIERS_PT_POV_modifiers,
- MATERIAL_PT_POV_sss,
- MATERIAL_MT_POV_sss_presets,
- MATERIAL_OT_POV_sss_add_preset,
- MATERIAL_PT_strand,
- MATERIAL_PT_POV_activate_node,
- MATERIAL_PT_POV_active_node,
- MATERIAL_PT_POV_specular,
- MATERIAL_PT_POV_mirror,
- MATERIAL_PT_POV_transp,
- MATERIAL_PT_POV_reflection,
- # MATERIAL_PT_POV_interior,
- MATERIAL_PT_POV_fade_color,
- MATERIAL_PT_POV_caustics,
- MATERIAL_PT_POV_replacement_text,
- TEXTURE_MT_POV_specials,
- TEXTURE_PT_POV_context_texture,
- TEXTURE_PT_POV_type,
- TEXTURE_PT_POV_preview,
- TEXTURE_PT_POV_parameters,
- TEXTURE_PT_POV_tex_gamma,
- OBJECT_PT_POV_obj_parameters,
- OBJECT_PT_POV_obj_sphere,
- OBJECT_PT_POV_obj_cylinder,
- OBJECT_PT_POV_obj_cone,
- OBJECT_PT_POV_obj_superellipsoid,
- OBJECT_PT_POV_obj_torus,
- OBJECT_PT_POV_obj_supertorus,
- OBJECT_PT_POV_obj_parametric,
- OBJECT_PT_povray_replacement_text,
- VIEW_MT_POV_primitives_add,
- VIEW_MT_POV_Basic_Shapes,
- VIEW_MT_POV_import,
- NODE_MT_POV_map_create,
- CAMERA_PT_POV_cam_dof,
- CAMERA_PT_POV_cam_nor,
- CAMERA_PT_POV_replacement_text,
- TEXT_OT_POV_insert,
- TEXT_MT_POV_insert,
- TEXT_PT_POV_custom_code,
- TEXT_MT_POV_templates,
- #TEXTURE_PT_POV_povray_texture_slots,
- #TEXTURE_UL_POV_texture_slots,
- MATERIAL_TEXTURE_SLOTS_UL_POV_layerlist,
- TEXTURE_OT_POV_texture_slot_add,
- TEXTURE_OT_POV_texture_slot_remove,
- TEXTURE_PT_POV_influence,
- TEXTURE_PT_POV_mapping,
-)
-
-
-def register():
- # from bpy.utils import register_class
-
- for cls in classes:
- register_class(cls)
-
- bpy.types.VIEW3D_MT_add.prepend(menu_func_add)
- bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
- bpy.types.TEXT_MT_templates.append(menu_func_templates)
- bpy.types.RENDER_PT_POV_radiosity.prepend(rad_panel_func)
- bpy.types.LIGHT_PT_POV_light.prepend(light_panel_func)
- # bpy.types.WORLD_PT_POV_world.prepend(world_panel_func)
- # was used for parametric objects but made the other addon unreachable on
- # unregister for other tools to use created a user action call instead
- # addon_utils.enable("add_mesh_extra_objects", default_set=False, persistent=True)
- # bpy.types.TEXTURE_PT_context_texture.prepend(TEXTURE_PT_POV_type)
-
- if not povCentricWorkspace in bpy.app.handlers.load_post:
- # print("Adding POV wentric workspace on load handlers list")
- bpy.app.handlers.load_post.append(povCentricWorkspace)
-
-def unregister():
- if povCentricWorkspace in bpy.app.handlers.load_post:
- # print("Removing POV wentric workspace from load handlers list")
- bpy.app.handlers.load_post.remove(povCentricWorkspace)
-
- # from bpy.utils import unregister_class
-
- # bpy.types.TEXTURE_PT_context_texture.remove(TEXTURE_PT_POV_type)
- # addon_utils.disable("add_mesh_extra_objects", default_set=False)
- # bpy.types.WORLD_PT_POV_world.remove(world_panel_func)
- bpy.types.LIGHT_PT_POV_light.remove(light_panel_func)
- bpy.types.RENDER_PT_POV_radiosity.remove(rad_panel_func)
- bpy.types.TEXT_MT_templates.remove(menu_func_templates)
- bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
- bpy.types.VIEW3D_MT_add.remove(menu_func_add)
-
- for cls in reversed(classes):
- if cls != TEXTURE_PT_context:
- unregister_class(cls)
diff --git a/render_povray/update_files.py b/render_povray/update_files.py
index 416e40d3..985f8468 100644..100755
--- a/render_povray/update_files.py
+++ b/render_povray/update_files.py
@@ -33,8 +33,22 @@ from bpy.props import (
EnumProperty,
)
+# Todo:
+# *update this file to just cover 2.79 to 3.xx and ui it from a Blender internal to pov menu
+# *as well as update from older pov > switch to QMC when pov 3.8 is out ?
+# *filter if possible files built in pre 2.79 versions. tell user their file is too old and may
+# be salvaged from older vesion of this operator from within latest stable blender 2.79 version.
+# else if bpy.app.version[0] == 2 and bpy.app.version[1] <= 92 and and bpy.app.version[1] >= 79:
+# warn users to update blender to 3.xx for creating their newer files then try to salvage
+# using this script
+#
+# if bpy.app.version[0] >= 3: # just test file created a)there or b)before, a) do nothing
+# "your version is relatively futureproof" > doing nothing
+# b)"use this operator to salvage your blends from latest stable 2.79"
+
def update2_0_0_9():
+ """Update properties from older Blender versions. The render API changed a lot up to 2.79."""
# Temporally register old props, so we can access their values.
register()
@@ -109,26 +123,16 @@ def update2_0_0_9():
"pov_refraction_type",
"pov_replacement_text",
]:
- old_mat_props[k] = getattr(bpy.types.Material, k)[1].get(
- 'default', None
- )
+ old_mat_props[k] = getattr(bpy.types.Material, k)[1].get('default', None)
# Get default values of pov texture props.
old_tex_props = {}
- for k in [
- "pov_tex_gamma_enable",
- "pov_tex_gamma_value",
- "pov_replacement_text",
- ]:
+ for k in ["pov_tex_gamma_enable", "pov_tex_gamma_value", "pov_replacement_text"]:
old_tex_props[k] = getattr(bpy.types.Texture, k)[1].get('default', None)
# Get default values of pov object props.
old_obj_props = {}
- for k in [
- "pov_importance_value",
- "pov_collect_photons",
- "pov_replacement_text",
- ]:
+ for k in ["pov_importance_value", "pov_collect_photons", "pov_replacement_text"]:
old_obj_props[k] = getattr(bpy.types.Object, k)[1].get('default', None)
# Get default values of pov camera props.
@@ -189,7 +193,7 @@ def update2_0_0_9():
class RenderCopySettings(bpy.types.Operator):
- """Update old POV properties to new ones"""
+ """Update old POV properties to new ones."""
bl_idname = "scene.pov_update_properties"
bl_label = "PovRay render: Update to script v0.0.9"
@@ -253,19 +257,13 @@ def register():
# Not a real pov option, just to know if we should write
Scene.pov_radio_enable = BoolProperty(
- name="Enable Radiosity",
- description="Enable POV-Rays radiosity calculation",
- default=False,
+ name="Enable Radiosity", description="Enable POV-Rays radiosity calculation", default=False
)
Scene.pov_radio_display_advanced = BoolProperty(
- name="Advanced Options",
- description="Show advanced options",
- default=False,
+ name="Advanced Options", description="Show advanced options", default=False
)
Scene.pov_media_enable = BoolProperty(
- name="Enable Media",
- description="Enable POV-Rays atmospheric media",
- default=False,
+ name="Enable Media", description="Enable POV-Rays atmospheric media", default=False
)
Scene.pov_media_samples = IntProperty(
name="Samples",
@@ -288,9 +286,7 @@ def register():
)
Scene.pov_baking_enable = BoolProperty(
- name="Enable Baking",
- description="Enable POV-Rays texture baking",
- default=False,
+ name="Enable Baking", description="Enable POV-Rays texture baking", default=False
)
Scene.pov_indentation_character = EnumProperty(
name="Indentation",
@@ -311,9 +307,7 @@ def register():
)
Scene.pov_comments_enable = BoolProperty(
- name="Enable Comments",
- description="Add comments to pov file",
- default=True,
+ name="Enable Comments", description="Add comments to pov file", default=True
)
# Real pov options
@@ -339,11 +333,7 @@ def register():
)
Scene.pov_antialias_depth = IntProperty(
- name="Antialias Depth",
- description="Depth of pixel for sampling",
- min=1,
- max=9,
- default=3,
+ name="Antialias Depth", description="Depth of pixel for sampling", min=1, max=9, default=3
)
Scene.pov_antialias_threshold = FloatProperty(
@@ -504,9 +494,7 @@ def register():
# max_sample - not available yet
Scene.pov_radio_media = BoolProperty(
- name="Media",
- description="Radiosity estimation can be affected by media",
- default=False,
+ name="Media", description="Radiosity estimation can be affected by media", default=False
)
Scene.pov_radio_minimum_reuse = FloatProperty(
@@ -529,9 +517,7 @@ def register():
)
Scene.pov_radio_normal = BoolProperty(
- name="Normals",
- description="Radiosity estimation can be affected by normals",
- default=False,
+ name="Normals", description="Radiosity estimation can be affected by normals", default=False
)
Scene.pov_radio_recursion_limit = IntProperty(
@@ -638,9 +624,7 @@ def register():
)
Mat.pov_fake_caustics = BoolProperty(
- name="Fake Caustics",
- description="use only (Fast) fake refractive caustics",
- default=True,
+ name="Fake Caustics", description="use only (Fast) fake refractive caustics", default=True
)
Mat.pov_fake_caustics_power = FloatProperty(
@@ -654,9 +638,7 @@ def register():
)
Mat.pov_photons_refraction = BoolProperty(
- name="Refractive Photon Caustics",
- description="more physically correct",
- default=False,
+ name="Refractive Photon Caustics", description="more physically correct", default=False
)
Mat.pov_photons_dispersion = FloatProperty(
@@ -752,9 +734,7 @@ def register():
# DOF Toggle
Cam.pov_dof_enable = BoolProperty(
- name="Depth Of Field",
- description="Enable POV-Ray Depth Of Field ",
- default=True,
+ name="Depth Of Field", description="Enable POV-Ray Depth Of Field ", default=True
)
# Aperture (Intensity of the Blur)
@@ -816,12 +796,12 @@ def unregister():
Obj = bpy.types.Object
Cam = bpy.types.Camera
Text = bpy.types.Text
- del Scene.pov_tempfiles_enable # CR
- del Scene.pov_scene_name # CR
- del Scene.pov_deletefiles_enable # CR
- del Scene.pov_scene_path # CR
- del Scene.pov_renderimage_path # CR
- del Scene.pov_list_lf_enable # CR
+ del Scene.pov_tempfiles_enable
+ del Scene.pov_scene_name
+ del Scene.pov_deletefiles_enable
+ del Scene.pov_scene_path
+ del Scene.pov_renderimage_path
+ del Scene.pov_list_lf_enable
del Scene.pov_radio_enable
del Scene.pov_radio_display_advanced
del Scene.pov_radio_adc_bailout
@@ -836,56 +816,56 @@ def unregister():
del Scene.pov_radio_nearest_count
del Scene.pov_radio_normal
del Scene.pov_radio_recursion_limit
- del Scene.pov_radio_pretrace_start # MR
- del Scene.pov_radio_pretrace_end # MR
- del Scene.pov_media_enable # MR
- del Scene.pov_media_samples # MR
- del Scene.pov_media_color # MR
- del Scene.pov_baking_enable # MR
- del Scene.pov_max_trace_level # MR
- del Scene.pov_photon_spacing # MR
- del Scene.pov_photon_max_trace_level # MR
- del Scene.pov_photon_adc_bailout # MR
- del Scene.pov_photon_gather_min # MR
- del Scene.pov_photon_gather_max # MR
- del Scene.pov_antialias_enable # CR
- del Scene.pov_antialias_method # CR
- del Scene.pov_antialias_depth # CR
- del Scene.pov_antialias_threshold # CR
- del Scene.pov_antialias_gamma # CR
- del Scene.pov_jitter_enable # CR
- del Scene.pov_jitter_amount # CR
- del Scene.pov_command_line_switches # CR
- del Scene.pov_indentation_character # CR
- del Scene.pov_indentation_spaces # CR
- del Scene.pov_comments_enable # CR
- del Mat.pov_irid_enable # MR
- del Mat.pov_mirror_use_IOR # MR
- del Mat.pov_mirror_metallic # MR
- del Mat.pov_conserve_energy # MR
- del Mat.pov_irid_amount # MR
- del Mat.pov_irid_thickness # MR
- del Mat.pov_irid_turbulence # MR
- del Mat.pov_interior_fade_color # MR
- del Mat.pov_caustics_enable # MR
- del Mat.pov_fake_caustics # MR
- del Mat.pov_fake_caustics_power # MR
- del Mat.pov_photons_refraction # MR
- del Mat.pov_photons_dispersion # MR
- del Mat.pov_photons_reflection # MR
- del Mat.pov_refraction_type # MR
- del Mat.pov_replacement_text # MR
- del Tex.pov_tex_gamma_enable # MR
- del Tex.pov_tex_gamma_value # MR
- del Tex.pov_replacement_text # MR
- del Obj.pov_importance_value # MR
- del Obj.pov_collect_photons # MR
- del Obj.pov_replacement_text # MR
- del Cam.pov_dof_enable # MR
- del Cam.pov_dof_aperture # MR
- del Cam.pov_dof_samples_min # MR
- del Cam.pov_dof_samples_max # MR
- del Cam.pov_dof_variance # MR
- del Cam.pov_dof_confidence # MR
- del Cam.pov_replacement_text # MR
- del Text.pov_custom_code # MR
+ del Scene.pov_radio_pretrace_start
+ del Scene.pov_radio_pretrace_end
+ del Scene.pov_media_enable
+ del Scene.pov_media_samples
+ del Scene.pov_media_color
+ del Scene.pov_baking_enable
+ del Scene.pov_max_trace_level
+ del Scene.pov_photon_spacing
+ del Scene.pov_photon_max_trace_level
+ del Scene.pov_photon_adc_bailout
+ del Scene.pov_photon_gather_min
+ del Scene.pov_photon_gather_max
+ del Scene.pov_antialias_enable
+ del Scene.pov_antialias_method
+ del Scene.pov_antialias_depth
+ del Scene.pov_antialias_threshold
+ del Scene.pov_antialias_gamma
+ del Scene.pov_jitter_enable
+ del Scene.pov_jitter_amount
+ del Scene.pov_command_line_switches
+ del Scene.pov_indentation_character
+ del Scene.pov_indentation_spaces
+ del Scene.pov_comments_enable
+ del Mat.pov_irid_enable
+ del Mat.pov_mirror_use_IOR
+ del Mat.pov_mirror_metallic
+ del Mat.pov_conserve_energy
+ del Mat.pov_irid_amount
+ del Mat.pov_irid_thickness
+ del Mat.pov_irid_turbulence
+ del Mat.pov_interior_fade_color
+ del Mat.pov_caustics_enable
+ del Mat.pov_fake_caustics
+ del Mat.pov_fake_caustics_power
+ del Mat.pov_photons_refraction
+ del Mat.pov_photons_dispersion
+ del Mat.pov_photons_reflection
+ del Mat.pov_refraction_type
+ del Mat.pov_replacement_text
+ del Tex.pov_tex_gamma_enable
+ del Tex.pov_tex_gamma_value
+ del Tex.pov_replacement_text
+ del Obj.pov_importance_value
+ del Obj.pov_collect_photons
+ del Obj.pov_replacement_text
+ del Cam.pov_dof_enable
+ del Cam.pov_dof_aperture
+ del Cam.pov_dof_samples_min
+ del Cam.pov_dof_samples_max
+ del Cam.pov_dof_variance
+ del Cam.pov_dof_confidence
+ del Cam.pov_replacement_text
+ del Text.pov_custom_code
diff --git a/rigify/ui.py b/rigify/ui.py
index 63118e67..6a3b81a6 100644
--- a/rigify/ui.py
+++ b/rigify/ui.py
@@ -756,14 +756,28 @@ class LayerInit(bpy.types.Operator):
return {'FINISHED'}
+def is_metarig(obj):
+ if not (obj and obj.data and obj.type == 'ARMATURE'):
+ return False
+ if 'rig_id' in obj.data:
+ return False
+ for b in obj.pose.bones:
+ if b.rigify_type != "":
+ return True
+ return False
+
class Generate(bpy.types.Operator):
"""Generates a rig from the active metarig armature"""
bl_idname = "pose.rigify_generate"
bl_label = "Rigify Generate Rig"
- bl_options = {'UNDO', 'INTERNAL'}
+ bl_options = {'UNDO'}
bl_description = 'Generates a rig from the active metarig armature'
+ @classmethod
+ def poll(cls, context):
+ return is_metarig(context.object)
+
def execute(self, context):
try:
generate.generate_rig(context, context.object)
@@ -818,40 +832,60 @@ class Sample(bpy.types.Operator):
"""Create a sample metarig to be modified before generating the final rig"""
bl_idname = "armature.metarig_sample_add"
- bl_label = "Add a sample metarig for a rig type"
- bl_options = {'UNDO', 'INTERNAL'}
+ bl_label = "Add Metarig Sample"
+ bl_options = {'UNDO'}
metarig_type: StringProperty(
name="Type",
description="Name of the rig type to generate a sample of",
maxlen=128,
+ options={'SKIP_SAVE'}
)
+ @classmethod
+ def poll(cls, context):
+ return context.mode == 'EDIT_ARMATURE'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+ col = layout.column()
+ build_type_list(context, context.window_manager.rigify_types)
+ col.prop(context.object.data, "active_feature_set")
+ col.prop_search(self, "metarig_type", context.window_manager, "rigify_types")
+
+ def invoke(self, context, event):
+ if self.metarig_type == "":
+ return context.window_manager.invoke_props_dialog(self)
+ return self.execute(context)
+
def execute(self, context):
- if context.mode == 'EDIT_ARMATURE' and self.metarig_type != "":
- try:
- rig = rig_lists.rigs[self.metarig_type]["module"]
- create_sample = rig.create_sample
- except (ImportError, AttributeError, KeyError):
- raise Exception("rig type '" + self.metarig_type + "' has no sample.")
- else:
- create_sample(context.active_object)
- finally:
- bpy.ops.object.mode_set(mode='EDIT')
+ if self.metarig_type == "":
+ self.report({'ERROR'}, "You must select a rig type to create a sample of.")
+ return {'CANCELLED'}
+ try:
+ rig = rig_lists.rigs[self.metarig_type]["module"]
+ create_sample = rig.create_sample
+ except (ImportError, AttributeError, KeyError):
+ raise Exception("rig type '" + self.metarig_type + "' has no sample.")
+ else:
+ create_sample(context.active_object)
+ finally:
+ bpy.ops.object.mode_set(mode='EDIT')
return {'FINISHED'}
class EncodeMetarig(bpy.types.Operator):
- """ Creates Python code that will generate the selected metarig.
- """
+ """Creates Python code that will generate the selected metarig"""
bl_idname = "armature.rigify_encode_metarig"
bl_label = "Rigify Encode Metarig"
bl_options = {'UNDO'}
@classmethod
def poll(self, context):
- return context.mode == 'EDIT_ARMATURE'
+ return context.mode == 'EDIT_ARMATURE' and is_metarig(context.object)
def execute(self, context):
name = "metarig.py"
@@ -865,21 +899,19 @@ class EncodeMetarig(bpy.types.Operator):
text = write_metarig(context.active_object, layers=True, func_name="create", groups=True, widgets=True)
text_block.write(text)
bpy.ops.object.mode_set(mode='EDIT')
-
+ self.report({'INFO'}, f"Metarig written to text datablock: {text_block.name}")
return {'FINISHED'}
class EncodeMetarigSample(bpy.types.Operator):
- """ Creates Python code that will generate the selected metarig
- as a sample.
- """
+ """Creates Python code that will generate the selected metarig as a sample"""
bl_idname = "armature.rigify_encode_metarig_sample"
bl_label = "Rigify Encode Metarig Sample"
bl_options = {'UNDO'}
@classmethod
def poll(self, context):
- return context.mode == 'EDIT_ARMATURE'
+ return context.mode == 'EDIT_ARMATURE' and is_metarig(context.object)
def execute(self, context):
name = "metarig_sample.py"
@@ -894,9 +926,31 @@ class EncodeMetarigSample(bpy.types.Operator):
text_block.write(text)
bpy.ops.object.mode_set(mode='EDIT')
+ self.report({'INFO'}, f"Metarig Sample written to text datablock: {text_block.name}")
return {'FINISHED'}
+class VIEW3D_MT_rigify(bpy.types.Menu):
+ bl_label = "Rigify"
+ bl_idname = "VIEW3D_MT_rigify"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator(Generate.bl_idname, text="Generate")
+
+ if context.mode == 'EDIT_ARMATURE':
+ layout.separator()
+ layout.operator(Sample.bl_idname)
+ layout.separator()
+ layout.operator(EncodeMetarig.bl_idname, text="Encode Metarig")
+ layout.operator(EncodeMetarigSample.bl_idname, text="Encode Metarig Sample")
+
+
+def draw_rigify_menu(self, context):
+ if is_metarig(context.object):
+ self.layout.menu(VIEW3D_MT_rigify.bl_idname)
+
class EncodeWidget(bpy.types.Operator):
""" Creates Python code that will generate the selected metarig.
"""
@@ -923,6 +977,10 @@ class EncodeWidget(bpy.types.Operator):
return {'FINISHED'}
+def draw_mesh_edit_menu(self, context):
+ self.layout.operator(EncodeWidget.bl_idname)
+ self.layout.separator()
+
def FktoIk(rig, window='ALL'):
@@ -1338,6 +1396,7 @@ classes = (
UpgradeMetarigTypes,
SwitchToLegacy,
Sample,
+ VIEW3D_MT_rigify,
EncodeMetarig,
EncodeMetarigSample,
EncodeWidget,
@@ -1359,6 +1418,9 @@ def register():
for cls in classes:
register_class(cls)
+ bpy.types.VIEW3D_MT_editor_menus.append(draw_rigify_menu)
+ bpy.types.VIEW3D_MT_edit_mesh.prepend(draw_mesh_edit_menu)
+
# Sub-modules.
rot_mode.register()
@@ -1373,4 +1435,7 @@ def unregister():
for cls in classes:
unregister_class(cls)
+ bpy.types.VIEW3D_MT_editor_menus.remove(draw_rigify_menu)
+ bpy.types.VIEW3D_MT_edit_mesh.remove(draw_mesh_edit_menu)
+
animation_unregister()
diff --git a/sun_position/__init__.py b/sun_position/__init__.py
index 0b15602b..e59a0932 100644
--- a/sun_position/__init__.py
+++ b/sun_position/__init__.py
@@ -34,8 +34,8 @@
bl_info = {
"name": "Sun Position",
"author": "Michael Martin",
- "version": (3, 1, 1),
- "blender": (2, 80, 0),
+ "version": (3, 1, 2),
+ "blender": (3, 0, 0),
"location": "World > Sun Position",
"description": "Show sun position with objects and/or sky texture",
"doc_url": "{BLENDER_MANUAL_URL}/addons/lighting/sun_position.html",
diff --git a/sun_position/hdr.py b/sun_position/hdr.py
index 27d6dca2..e117e3b3 100644
--- a/sun_position/hdr.py
+++ b/sun_position/hdr.py
@@ -19,8 +19,8 @@
# -*- coding: utf-8 -*-
import bpy
+from bpy.props import FloatProperty, FloatVectorProperty
import gpu
-import bgl
from gpu_extras.batch import batch_for_shader
from mathutils import Vector
from math import sqrt, pi, atan2, asin
@@ -60,6 +60,7 @@ def draw_callback_px(self, context):
nt = context.scene.world.node_tree.nodes
env_tex_node = nt.get(context.scene.sun_pos_properties.hdr_texture)
image = env_tex_node.image
+ texture = gpu.texture.from_image(image)
if self.area != context.area:
return
@@ -82,16 +83,12 @@ def draw_callback_px(self, context):
{"pos" : coords,
"texCoord" : uv_coords})
- bgl.glActiveTexture(bgl.GL_TEXTURE0)
- bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)
-
-
with gpu.matrix.push_pop():
gpu.matrix.translate(position)
gpu.matrix.scale(scale)
shader.bind()
- shader.uniform_int("image", 0)
+ shader.uniform_sampler("image", texture)
shader.uniform_float("exposure", self.exposure)
batch.draw(shader)
@@ -119,7 +116,9 @@ class SUNPOS_OT_ShowHdr(bpy.types.Operator):
bl_idname = "world.sunpos_show_hdr"
bl_label = "Sync Sun to Texture"
- exposure = 1.0
+ exposure: FloatProperty(name="Exposure", default=1.0)
+ scale: FloatProperty(name="Scale", default=1.0)
+ offset: FloatVectorProperty(name="Offset", default=(0.0, 0.0), size=2, subtype='COORDINATES')
@classmethod
def poll(self, context):
@@ -267,8 +266,6 @@ class SUNPOS_OT_ShowHdr(bpy.types.Operator):
self.is_panning = False
self.mouse_prev_x = 0.0
self.mouse_prev_y = 0.0
- self.offset = Vector((0.0, 0.0))
- self.scale = 1.0
# Get at least one 3D View
area_3d = None
diff --git a/sun_position/north.py b/sun_position/north.py
index 0dbe7e4e..0c0a41af 100644
--- a/sun_position/north.py
+++ b/sun_position/north.py
@@ -17,7 +17,6 @@
# ##### END GPL LICENSE BLOCK #####
import bpy
-import bgl
import math
import gpu
from gpu_extras.batch import batch_for_shader
@@ -94,10 +93,9 @@ else:
shader.uniform_float("u_ViewProjectionMatrix", matrix)
shader.uniform_float("u_Resolution", (bpy.context.region.width, bpy.context.region.height))
shader.uniform_float("u_Color", color)
- bgl.glLineWidth(2.0)
+ gpu.state.line_width_set(2.0)
batch.draw(shader)
-
_handle = None