diff options
author | Maurice Raybaud <mauriceraybaud@hotmail.fr> | 2017-01-29 23:28:41 +0300 |
---|---|---|
committer | Maurice Raybaud <mauriceraybaud@hotmail.fr> | 2017-01-29 23:28:41 +0300 |
commit | 6f40579d5bd29e235b8aa372297de5eabf23aab7 (patch) | |
tree | af9e95de45d0feb630600712e111ef8e2a9351fc /render_povray | |
parent | bafb8d353d64aa62be4dfeb1892aab4e2625053d (diff) |
Added Basic Nodes support by Lanuhum
Diffstat (limited to 'render_povray')
-rw-r--r-- | render_povray/__init__.py | 577 | ||||
-rw-r--r-- | render_povray/nodes.py | 1299 | ||||
-rw-r--r-- | render_povray/primitives.py | 84 | ||||
-rw-r--r-- | render_povray/render.py | 42 | ||||
-rw-r--r-- | render_povray/shading.py | 520 | ||||
-rw-r--r-- | render_povray/ui.py | 151 |
6 files changed, 2609 insertions, 64 deletions
diff --git a/render_povray/__init__.py b/render_povray/__init__.py index 31b7671b..85c4e608 100644 --- a/render_povray/__init__.py +++ b/render_povray/__init__.py @@ -1,4 +1,4 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### +# ##### 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 @@ -19,7 +19,7 @@ # <pep8 compliant> bl_info = { - "name": "POV-Ray 3.7", + "name": "POVRAY-3.7", "author": "Campbell Barton, Silvio Falcinelli, Maurice Raybaud, " "Constantin Rahn, Bastien Montagne, Leonid Desyatkov", "version": (0, 0, 9), @@ -41,10 +41,12 @@ if "bpy" in locals(): else: import bpy import addon_utils # To use some other addons + import nodeitems_utils #for Nodes + from nodeitems_utils import NodeCategory, NodeItem #for Nodes from bpy.types import ( AddonPreferences, PropertyGroup, - Operator, + #Operator, ) from bpy.props import ( StringProperty, @@ -450,6 +452,548 @@ class RenderPovSettingsMaterial(PropertyGroup): 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) + + +############################################################################### +# Povray Nodes +############################################################################### +class PovraySocketUniversal(bpy.types.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(bpy.types.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(bpy.types.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('') + 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(bpy.types.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('') + 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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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("Pattern") + else: + layout.prop(self, "default_value", text=text) + + def draw_color(self, context, node): + return (1, 1, 1, 1) + +class PovraySocketColor(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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. ############################################################################### @@ -1017,11 +1561,12 @@ class RenderPovSettingsObject(PropertyGroup): ("grid", "Grid", ""), ("mesh", "Mesh", "")), default="mesh") - # shape_as_light = StringProperty(name="Light",maxlen=1024) - # object_ior = FloatProperty( - # name="IOR", description="IOR", - # min=1.0, max=10.0,default=1.0) + 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) @@ -1482,7 +2027,16 @@ class PovrayPreferences(AddonPreferences): layout.prop(self, "branch_feature_set_povray") layout.prop(self, "filepath_povray") - + + + + + + + + + + def register(): bpy.utils.register_module(__name__) @@ -1492,6 +2046,9 @@ def register(): 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.Material.pov = PointerProperty(type=RenderPovSettingsMaterial) bpy.types.Texture.pov = PointerProperty(type=RenderPovSettingsTexture) @@ -1502,14 +2059,16 @@ def register(): def unregister(): - #bpy.types.TEXTURE_PT_context_texture.remove(TEXTURE_PT_povray_type) del bpy.types.Scene.pov del bpy.types.Material.pov del bpy.types.Texture.pov del bpy.types.Object.pov del bpy.types.Camera.pov 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.INFO_MT_file_import.remove(ui.menu_func_import) bpy.types.INFO_MT_add.remove(ui.menu_func_add) diff --git a/render_povray/nodes.py b/render_povray/nodes.py new file mode 100644 index 00000000..41b0caf1 --- /dev/null +++ b/render_povray/nodes.py @@ -0,0 +1,1299 @@ +# ##### 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.types import Node, ShaderNodeTree, CompositorNodeTree, TextureNodeTree#, NodeSocket + + +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 {'LAMP'}: + ma = ob.active_material + if ma != 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("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("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(percentage=0.8,align=True) + split.prop_search(self,"image",context.blend_data,"images",text="") + split.operator("pov.imageopen",text="",icon="FILESEL") + if im != 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(percentage=0.8,align=True) + split.prop_search(self,"image",context.blend_data,"images",text="") + split.operator("pov.imageopen",text="",icon="FILESEL") + if im != 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="FILESEL") + if im != 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="FILESEL") + if im != 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(percentage=0.8,align=True) + split.prop_search(self,"image",context.blend_data,"images",text="") + split.operator("pov.imageopen",text="",icon="FILESEL") + if im != 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(percentage=0.8,align=True) + split.prop_search(self,"image",context.blend_data,"images",text="") + split.operator("pov.imageopen",text="",icon="FILESEL") + if im != 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("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("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("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("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("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('Value') + row.label('Height') + row.label('Slope') + + def draw_buttons_ext(self, context, layout): + + layout.operator("pov.nodeinputadd") + row = layout.row() + row.label('Value') + row.label('Height') + row.label('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("Color Ramps:") + + def draw_label(self): + return "Color Map" + + +################################################################################## +#################################Operators######################################## +################################################################################## + + +class NODE_OT_iso_add(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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(bpy.types.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 + # scene = context.scene + # scene.update() + # return {'FINISHED'} + +class PovrayPatternNode(bpy.types.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(bpy.types.Operator): + '''Operator update preview material''' + bl_idname = "node.updatepreview" + bl_label = "Update preview" + + def execute(self, context): + scene=context.scene + ob=context.object + for obj in scene.objects: + if obj != ob: + scene.objects.active=obj + 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(bpy.types.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'} + +
\ No newline at end of file diff --git a/render_povray/primitives.py b/render_povray/primitives.py index c7fd6999..f053f29f 100644 --- a/render_povray/primitives.py +++ b/render_povray/primitives.py @@ -1,6 +1,27 @@ +# ##### 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> + ############ To get POV-Ray specific objects In and Out of Blender ########### import bpy +import os.path from bpy_extras.io_utils import ImportHelper from bpy_extras import object_utils from math import atan, pi, degrees, sqrt, cos, sin @@ -1505,36 +1526,8 @@ class ImportPOV(bpy.types.Operator, ImportHelper): #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 - + r,g,b,t = float(cache[-5]),float(cache[-4]),float(cache[-3]),float(cache[-2]) + color = (r,g,b,t) if colors == [] or (colors != [] and color not in colors): colors.append(color) name = ob.name+"_mat" @@ -1542,11 +1535,13 @@ class ImportPOV(bpy.types.Operator, ImportHelper): 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, value in enumerate(colors): - if color == value: + for i in range(len(colors)): + if color == colors[i]: ob.data.materials.append(bpy.data.materials[matNames[i]]) for file in self.files: print ("Importing file: "+ file.name) @@ -1693,36 +1688,27 @@ class ImportPOV(bpy.types.Operator, ImportHelper): 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]) + 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) 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################## + sphere_search = False + ##################End Primitives Import################## if word == '#declare': name_search = True if name_search: diff --git a/render_povray/render.py b/render_povray/render.py index e08fdf3d..ae23dd27 100644 --- a/render_povray/render.py +++ b/render_povray/render.py @@ -34,6 +34,7 @@ from imghdr import what #imghdr is a python lib to identify image file types from . import df3 # for smoke rendering from . import shading # for BI POV haders 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): @@ -2856,10 +2857,15 @@ def write_pov(filename, scene=None, info_callback=None): 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: + if material and material.pov.material_use_nodes == False: # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # Multiply diffuse with SSS Color if material.subsurface_scattering.use: diffuse_color = [i * j for i, j in zip(material.subsurface_scattering.color[:], material.diffuse_color[:])] @@ -2914,8 +2920,8 @@ def write_pov(filename, scene=None, info_callback=None): #when no material slot exists, material=None - - if material and ob.active_material is not 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) @@ -2927,6 +2933,11 @@ def write_pov(filename, scene=None, info_callback=None): 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") @@ -2964,6 +2975,7 @@ def write_pov(filename, scene=None, info_callback=None): else: material = me_materials[material_index] for i1, i2, i3 in indices: + ci1 = ci2 = ci3 = f.material_index if me.vertex_colors: #and material.use_vertex_color_paint: # Color per vertex - vertex color @@ -2974,6 +2986,8 @@ def write_pov(filename, scene=None, info_callback=None): 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.subsurface_scattering.use: @@ -3408,7 +3422,25 @@ def write_pov(filename, scene=None, info_callback=None): shading.writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments, uniqueName, materialNames, None) # default material for material in bpy.data.materials: if material.users > 0: - shading.writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments, uniqueName, materialNames, material) + if material.pov.material_use_nodes: + ntree = material.node_tree + povMatName=string_strip_hyphen(bpy.path.clean_name(material.name)) + if len(ntree.nodes)==0: + file.write('#declare %s = texture {%s}\n'%(povMatName,color)) + else: + shading.write_nodes(scene,povMatName,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=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName + else: + file.write('#declare %s = texture {%s}\n'%(povMatName,color)) + else: + shading.writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments, uniqueName, materialNames, material) # attributes are all the variables needed by the other python file... if comments: file.write("\n") @@ -3926,7 +3958,7 @@ class PovrayRender(bpy.types.RenderEngine): else: print("***POV FILE NOT FOUND***") - print("***POV FINISHED***") + print("***POV FILE FINISHED***") #print(filename_log) #bring the pov log to blender console with proper path? with open(self._temp_file_log) as f: # The with keyword automatically closes the file when you are done diff --git a/render_povray/shading.py b/render_povray/shading.py index 9ced6000..81fd2376 100644 --- a/render_povray/shading.py +++ b/render_povray/shading.py @@ -1179,3 +1179,523 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image, mappingNor)) tabWrite("}\n") # THEN IT CAN CLOSE LAST LAYER OF TEXTURE + +def string_strip_hyphen(name): + return name.replace("-", "") +# WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +def write_nodes(scene,povMatName,ntree,file): + declareNodes=[] + scene=bpy.context.scene + for node in ntree.nodes: + povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName + if node.bl_idname == "PovrayFinishNode" and node.outputs["Finish"].is_linked: + file.write('#declare %s = finish {\n'%povNodeName) + emission=node.inputs["Emission"].default_value + if node.inputs["Emission"].is_linked: + pass + 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.inputs["Intensity"].is_linked: + pass + else: + 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: + albedo = "albedo" + 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) + if link.from_node.inputs["Crand"].is_linked: + pass + else: + crand=link.from_node.inputs["Crand"].default_value + if crand > 0: + file.write(' crand %.4g\n'%crand) + + + 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[:] + 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" + if link.from_node.inputs["Intensity"].is_linked: + pass + else: + 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: + 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 {'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) + + 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) + + 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="" + 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) + + if link.from_node.inputs["Exponent"].is_linked: + pass + else: + 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) + + if link.from_node.inputs["Metallic"].is_linked: + pass + else: + 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["Conserve energy"].is_linked: + pass + else: + if link.from_node.inputs["Conserve energy"].default_value==True: + conserve="conserve_energy" + + file.write(' %s}\n %s\n'%(fresnel,conserve)) + + 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 + if link.from_node.inputs["Amount"].is_linked: + pass + else: + 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) + + if link.from_node.inputs["Turbulence"].is_linked: + pass + else: + falloff=link.from_node.inputs["Turbulence"].default_value + file.write(' turbulence %.4g}\n'%turbulence) + + file.write('}\n') + + for node in ntree.nodes: + povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName + 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)) + + for node in ntree.nodes: + povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName + if node.bl_idname == "PovrayColorImageNode" and node.outputs["Pigment"].is_linked: + declareNodes.append(node.name) + if node.image == "": + file.write('#declare %s = pigment { color rgb 0.8}\n'%(povNodeName)) + else: + im=bpy.data.images[node.image] + if im.filepath and os.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 = pigment {%s image_map {\n'%(povNodeName,uv)) + premul="off" + if node.premultiplied: + 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') + + for node in ntree.nodes: + povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName + if node.bl_idname == "PovrayImagePatternNode" and node.outputs["Pattern"].is_linked: + declareNodes.append(node.name) + if node.image != "": + im=bpy.data.images[node.image] + if im.filepath and os.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 node.premultiplied: + 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') + + for node in ntree.nodes: + povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName + 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)): + 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 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 + 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) + + + + for node in ntree.nodes: + povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName + 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 + 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)) + + + for node in ntree.nodes: + povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName + 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) + 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 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 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) + + for i in range(0,len(ntree.nodes)): + for node in ntree.nodes: + 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 + 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 declare: + povNodeName=string_strip_hyphen(bpy.path.clean_name(node.name))+"_%s"%povMatName + 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": + w_type = link.from_node.warp_type + 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="" + if node.inputs[0].is_linked: + for link in ntree.links: + 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 + 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="" + for link in ntree.links: + 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 + if link.from_node.amount_y > 1: + 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 + + 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 + for link in ntree.links: + 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: + x = link.from_node.inputs["Turb X"].default_value + + if link.from_node.inputs["Turb Y"].is_linked: + pass + else: + y = link.from_node.inputs["Turb Y"].default_value + + if link.from_node.inputs["Turb Z"].is_linked: + pass + else: + z = link.from_node.inputs["Turb Z"].default_value + + if link.from_node.inputs["Octaves"].is_linked: + pass + else: + d = link.from_node.inputs["Octaves"].default_value + + if link.from_node.inputs["Lambda"].is_linked: + pass + else: + e = link.from_node.inputs["Lambda"].default_value + + if link.from_node.inputs["Omega"].is_linked: + pass + else: + f = link.from_node.inputs["Omega"].default_value + + if link.from_node.inputs["Frequency"].is_linked: + pass + else: + g = link.from_node.inputs["Frequency"].default_value + + if link.from_node.inputs["Phase"].is_linked: + pass + 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') + if node.inputs["Color ramp"].is_linked: + for link in ntree.links: + if link.to_node==node and link.from_node.bl_idname=="ShaderNodeValToRGB": + els = link.from_node.color_ramp.elements + 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 + 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 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)) + 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 + 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 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)) + 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)) + 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 modifier: + file.write(' %s %s %s %s %s %s'%(turb,octv,lmbd,omg,freq,pha)) + file.write('}\n') + declareNodes.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)) diff --git a/render_povray/ui.py b/render_povray/ui.py index f0c361d9..fcdb25a9 100644 --- a/render_povray/ui.py +++ b/render_povray/ui.py @@ -59,6 +59,8 @@ for member in dir(properties_material): properties_material.MATERIAL_PT_game_settings, properties_material.MATERIAL_PT_physics): try: + #mat=context.material + #if mat and mat.type == "SURFACE" and (engine in cls.COMPAT_ENGINES) and not (mat.pov.material_use_nodes or mat.use_nodes): subclass.COMPAT_ENGINES.add('POVRAY_RENDER') except: pass @@ -86,6 +88,7 @@ for member in dir(properties_particle): # add all "particle" panels from blende pass del properties_particle + class RenderButtonsPanel(): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' @@ -611,11 +614,90 @@ class RENDER_PT_povray_media(WorldButtonsPanel, bpy.types.Panel): ## ## layout.active = scene.pov.baking_enable +class MATERIAL_PT_povray_activate_node(MaterialButtonsPanel, bpy.types.Panel): + 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.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_povray_active_node(MaterialButtonsPanel, bpy.types.Panel): + 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.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("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("Inputs:") + for socket in value_inputs: + row = layout.row() + socket.draw(context, row, node, socket.name) + else: + layout.label("No active nodes!") + class MATERIAL_PT_povray_reflection(MaterialButtonsPanel, bpy.types.Panel): bl_label = "POV-Ray Reflection" COMPAT_ENGINES = {'POVRAY_RENDER'} + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + mat=context.material + ob = context.object + return mat and mat.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 @@ -644,6 +726,14 @@ class MATERIAL_PT_povray_fade_color(MaterialButtonsPanel, bpy.types.Panel): bl_label = "POV-Ray 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.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 @@ -665,6 +755,15 @@ class MATERIAL_PT_povray_caustics(MaterialButtonsPanel, bpy.types.Panel): 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.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: @@ -702,6 +801,7 @@ class MATERIAL_PT_povray_replacement_text(MaterialButtonsPanel, bpy.types.Panel) bl_label = "Custom POV Code" COMPAT_ENGINES = {'POVRAY_RENDER'} + def draw(self, context): layout = self.layout @@ -1377,6 +1477,55 @@ def menu_func_import(self, context): 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_map_create_menu(bpy.types.Menu): + """Create maps""" + bl_idname = "Node_map_create_menu" + 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_map_create_menu") + 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 ############################################################################### @@ -1424,7 +1573,7 @@ class CAMERA_PT_povray_replacement_text(CameraDataButtonsPanel, bpy.types.Panel) class TEXT_PT_povray_custom_code(TextButtonsPanel, bpy.types.Panel): - bl_label = "P.O.V-Ray" + bl_label = "POV-Ray" COMPAT_ENGINES = {'POVRAY_RENDER'} def draw(self, context): |