# ##### 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 ##### # import bpy from bpy.utils import register_class 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 {'LIGHT'}: ma = ob.active_material if ma is not None: nt_name = ma.node_tree if nt_name != '': return nt_name, ma, ma return (None, None, None) def update(self): self.refresh = True ################### output ############################################################################################# class PovrayOutputNode(Node, ObjectNodeTree): '''Output''' bl_idname = 'PovrayOutputNode' bl_label = 'Output' bl_icon = 'SOUND' def init(self, context): self.inputs.new('PovraySocketTexture', "Texture") def draw_buttons(self, context, layout): ob=context.object layout.prop(ob.pov, "object_ior",slider=True) def draw_buttons_ext(self, context, layout): ob=context.object layout.prop(ob.pov, "object_ior",slider=True) def draw_label(self): return "Output" ################### material ########################################################################################### class PovrayTextureNode(Node, ObjectNodeTree): '''Texture''' bl_idname = 'PovrayTextureNode' bl_label = 'Simple texture' bl_icon = 'SOUND' def init(self, context): color=self.inputs.new('PovraySocketColor', "Pigment") color.default_value=(1,1,1) normal=self.inputs.new('NodeSocketFloat', "Normal") normal.hide_value=True finish=self.inputs.new('NodeSocketVector', "Finish") finish.hide_value=True self.outputs.new('PovraySocketTexture', "Texture") def draw_label(self): return "Simple texture" class PovrayFinishNode(Node, ObjectNodeTree): '''Finish''' bl_idname = 'PovrayFinishNode' bl_label = 'Finish' bl_icon = 'SOUND' def init(self, context): self.inputs.new('PovraySocketFloat_0_1', "Emission") ambient=self.inputs.new('NodeSocketVector', "Ambient") ambient.hide_value=True diffuse=self.inputs.new('NodeSocketVector', "Diffuse") diffuse.hide_value=True specular=self.inputs.new('NodeSocketVector', "Highlight") specular.hide_value=True mirror=self.inputs.new('NodeSocketVector', "Mirror") mirror.hide_value=True iridescence=self.inputs.new('NodeSocketVector', "Iridescence") iridescence.hide_value=True subsurface=self.inputs.new('NodeSocketVector', "Translucency") subsurface.hide_value=True self.outputs.new('NodeSocketVector', "Finish") def draw_label(self): return "Finish" class PovrayDiffuseNode(Node, ObjectNodeTree): '''Diffuse''' bl_idname = 'PovrayDiffuseNode' bl_label = 'Diffuse' bl_icon = 'SOUND' def init(self, context): intensity=self.inputs.new('PovraySocketFloat_0_1', "Intensity") intensity.default_value=0.8 albedo=self.inputs.new('NodeSocketBool', "Albedo") albedo.default_value=False brilliance=self.inputs.new('PovraySocketFloat_0_10', "Brilliance") brilliance.default_value=1.8 self.inputs.new('PovraySocketFloat_0_1', "Crand") self.outputs.new('NodeSocketVector', "Diffuse") def draw_label(self): return "Diffuse" class PovrayPhongNode(Node, ObjectNodeTree): '''Phong''' bl_idname = 'PovrayPhongNode' bl_label = 'Phong' bl_icon = 'SOUND' def init(self, context): albedo=self.inputs.new('NodeSocketBool', "Albedo") intensity=self.inputs.new('PovraySocketFloat_0_1', "Intensity") intensity.default_value=0.8 phong_size=self.inputs.new('PovraySocketInt_0_256', "Size") phong_size.default_value=60 metallic=self.inputs.new('PovraySocketFloat_0_1', "Metallic") self.outputs.new('NodeSocketVector', "Phong") def draw_label(self): return "Phong" class PovraySpecularNode(Node, ObjectNodeTree): '''Specular''' bl_idname = 'PovraySpecularNode' bl_label = 'Specular' bl_icon = 'SOUND' def init(self, context): albedo=self.inputs.new('NodeSocketBool', "Albedo") intensity=self.inputs.new('PovraySocketFloat_0_1', "Intensity") intensity.default_value=0.8 roughness=self.inputs.new('PovraySocketFloat_0_1', "Roughness") roughness.default_value=0.02 metallic=self.inputs.new('PovraySocketFloat_0_1', "Metallic") self.outputs.new('NodeSocketVector', "Specular") def draw_label(self): return "Specular" class PovrayMirrorNode(Node, ObjectNodeTree): '''Mirror''' bl_idname = 'PovrayMirrorNode' bl_label = 'Mirror' bl_icon = 'SOUND' def init(self, context): color=self.inputs.new('PovraySocketColor', "Color") color.default_value=(1,1,1) metallic=self.inputs.new('PovraySocketFloat_0_1', "Metallic") metallic.default_value=1.0 exponent=self.inputs.new('PovraySocketFloat_0_1', "Exponent") exponent.default_value=1.0 self.inputs.new('PovraySocketFloat_0_1', "Falloff") self.inputs.new('NodeSocketBool', "Fresnel") self.inputs.new('NodeSocketBool', "Conserve energy") self.outputs.new('NodeSocketVector', "Mirror") def draw_label(self): return "Mirror" class PovrayAmbientNode(Node, ObjectNodeTree): '''Ambient''' bl_idname = 'PovrayAmbientNode' bl_label = 'Ambient' bl_icon = 'SOUND' def init(self, context): self.inputs.new('PovraySocketColor', "Ambient") self.outputs.new('NodeSocketVector', "Ambient") def draw_label(self): return "Ambient" class PovrayIridescenceNode(Node, ObjectNodeTree): '''Iridescence''' bl_idname = 'PovrayIridescenceNode' bl_label = 'Iridescence' bl_icon = 'SOUND' def init(self, context): amount=self.inputs.new('NodeSocketFloat', "Amount") amount.default_value=0.25 thickness=self.inputs.new('NodeSocketFloat', "Thickness") thickness.default_value=1 self.inputs.new('NodeSocketFloat', "Turbulence") self.outputs.new('NodeSocketVector', "Iridescence") def draw_label(self): return "Iridescence" class PovraySubsurfaceNode(Node, ObjectNodeTree): '''Subsurface''' bl_idname = 'PovraySubsurfaceNode' bl_label = 'Subsurface' bl_icon = 'SOUND' def init(self, context): translucency=self.inputs.new('NodeSocketColor', "Translucency") translucency.default_value=(0,0,0,1) energy=self.inputs.new('PovraySocketInt_0_256', "Energy") energy.default_value=20 self.outputs.new('NodeSocketVector', "Translucency") def draw_buttons(self, context, layout): scene=context.scene layout.prop(scene.pov, "sslt_enable",text="SSLT") def draw_buttons_ext(self, context, layout): scene=context.scene layout.prop(scene.pov, "sslt_enable",text="SSLT") def draw_label(self): return "Subsurface" ##################################################################################################### class PovrayMappingNode(Node, ObjectNodeTree): '''Mapping''' bl_idname = 'PovrayMappingNode' bl_label = 'Mapping' bl_icon = 'SOUND' warp_type: EnumProperty( name="Warp Types", description="Select the type of warp", items=( ('cubic', "Cubic", ""), ('cylindrical', "Cylindrical", ""),('planar', "Planar", ""), ('spherical', "Spherical", ""),('toroidal', "Toroidal", ""), ('uv_mapping', "UV", ""), ('NONE', "None", "No indentation")), default='NONE') warp_orientation: EnumProperty( name="Warp Orientation", description="Select the orientation of warp", items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")), default='y') warp_dist_exp: FloatProperty( name="Distance exponent", description="Distance exponent", min=0.0, max=100.0, default=1.0) warp_tor_major_radius: FloatProperty( name="Major radius", description="Torus is distance from major radius", min=0.0, max=5.0, default=1.0) def init(self, context): self.outputs.new('NodeSocketVector', "Mapping") def draw_buttons(self, context, layout): column=layout.column() column.prop(self,"warp_type",text="Warp type") if self.warp_type in {'toroidal','spherical','cylindrical','planar'}: column.prop(self,"warp_orientation",text="Orientation") column.prop(self,"warp_dist_exp",text="Exponent") if self.warp_type=='toroidal': column.prop(self,"warp_tor_major_radius",text="Major R") def draw_buttons_ext(self, context, layout): column=layout.column() column.prop(self,"warp_type",text="Warp type") if self.warp_type in {'toroidal','spherical','cylindrical','planar'}: column.prop(self,"warp_orientation",text="Orientation") column.prop(self,"warp_dist_exp",text="Exponent") if self.warp_type=='toroidal': column.prop(self,"warp_tor_major_radius",text="Major R") def draw_label(self): return "Mapping" class PovrayMultiplyNode(Node, ObjectNodeTree): '''Multiply''' bl_idname = 'PovrayMultiplyNode' bl_label = 'Multiply' bl_icon = 'SOUND' amount_x : FloatProperty( name="X", description="Number of repeats", min=1.0, max=10000.0, default=1.0) amount_y : FloatProperty( name="Y", description="Number of repeats", min=1.0, max=10000.0, default=1.0) amount_z : FloatProperty( name="Z", description="Number of repeats", min=1.0, max=10000.0, default=1.0) def init(self, context): self.outputs.new('NodeSocketVector', "Amount") def draw_buttons(self, context, layout): column=layout.column() column.label(text="Amount") row=column.row(align=True) row.prop(self,"amount_x") row.prop(self,"amount_y") row.prop(self,"amount_z") def draw_buttons_ext(self, context, layout): column=layout.column() column.label(text="Amount") row=column.row(align=True) row.prop(self,"amount_x") row.prop(self,"amount_y") row.prop(self,"amount_z") def draw_label(self): return "Multiply" class PovrayTransformNode(Node, ObjectNodeTree): '''Transform''' bl_idname = 'PovrayTransformNode' bl_label = 'Transform' bl_icon = 'SOUND' def init(self, context): self.inputs.new('PovraySocketFloatUnlimited', "Translate x") self.inputs.new('PovraySocketFloatUnlimited', "Translate y") self.inputs.new('PovraySocketFloatUnlimited', "Translate z") self.inputs.new('PovraySocketFloatUnlimited', "Rotate x") self.inputs.new('PovraySocketFloatUnlimited', "Rotate y") self.inputs.new('PovraySocketFloatUnlimited', "Rotate z") sX = self.inputs.new('PovraySocketFloatUnlimited', "Scale x") sX.default_value = 1.0 sY = self.inputs.new('PovraySocketFloatUnlimited', "Scale y") sY.default_value = 1.0 sZ = self.inputs.new('PovraySocketFloatUnlimited', "Scale z") sZ.default_value = 1.0 self.outputs.new('NodeSocketVector', "Transform") def draw_label(self): return "Transform" class PovrayValueNode(Node, ObjectNodeTree): '''Value''' bl_idname = 'PovrayValueNode' bl_label = 'Value' bl_icon = 'SOUND' def init(self, context): self.outputs.new('PovraySocketUniversal', "Value") def draw_label(self): return "Value" class PovrayModifierNode(Node, ObjectNodeTree): '''Modifier''' bl_idname = 'PovrayModifierNode' bl_label = 'Modifier' bl_icon = 'SOUND' def init(self, context): turb_x=self.inputs.new('PovraySocketFloat_0_10', "Turb X") turb_x.default_value=0.1 turb_y=self.inputs.new('PovraySocketFloat_0_10', "Turb Y") turb_y.default_value=0.1 turb_z=self.inputs.new('PovraySocketFloat_0_10', "Turb Z") turb_z.default_value=0.1 octaves=self.inputs.new('PovraySocketInt_1_9', "Octaves") octaves.default_value=1 lambat=self.inputs.new('PovraySocketFloat_0_10', "Lambda") lambat.default_value=2.0 omega=self.inputs.new('PovraySocketFloat_0_10', "Omega") omega.default_value=0.5 freq=self.inputs.new('PovraySocketFloat_0_10', "Frequency") freq.default_value=2.0 self.inputs.new('PovraySocketFloat_0_10', "Phase") self.outputs.new('NodeSocketVector', "Modifier") def draw_label(self): return "Modifier" class PovrayPigmentNode(Node, ObjectNodeTree): '''Pigment''' bl_idname = 'PovrayPigmentNode' bl_label = 'Color' def init(self, context): color = self.inputs.new('PovraySocketColor', "Color") color.default_value = (1,1,1) povfilter = self.inputs.new('PovraySocketFloat_0_1', "Filter") transmit = self.inputs.new('PovraySocketFloat_0_1', "Transmit") self.outputs.new('NodeSocketColor', "Pigment") def draw_label(self): return "Color" class PovrayColorImageNode(Node, ObjectNodeTree): '''ColorImage''' bl_idname = 'PovrayColorImageNode' bl_label = 'Image map' map_type: bpy.props.EnumProperty( name="Map type", description="", items=( ('uv_mapping', "UV", ""), ('0', "Planar", "Default planar mapping"), ('1', "Spherical", "Spherical mapping"), ('2', "Cylindrical", "Cylindrical mapping"), ('5', "Torroidal", "Torus or donut shaped mapping")), default='0') image: StringProperty(maxlen=1024) # , subtype="FILE_PATH" interpolate: EnumProperty( name="Interpolate", description="Adding the interpolate keyword can smooth the jagged look of a bitmap", items=( ('2', "Bilinear", "Gives bilinear interpolation"), ('4', "Normalized", "Gives normalized distance"), ), default='2') premultiplied: BoolProperty(default=False) once: BoolProperty(description="Not to repeat", default=False) def init(self, context): gamma=self.inputs.new('PovraySocketFloat_000001_10', "Gamma") gamma.default_value=2.0 transmit=self.inputs.new('PovraySocketFloat_0_1', "Transmit") povfilter=self.inputs.new('PovraySocketFloat_0_1', "Filter") mapping=self.inputs.new('NodeSocketVector', "Mapping") mapping.hide_value=True transform=self.inputs.new('NodeSocketVector', "Transform") transform.hide_value=True modifier=self.inputs.new('NodeSocketVector', "Modifier") modifier.hide_value=True self.outputs.new('NodeSocketColor', "Pigment") def draw_buttons(self, context, layout): column=layout.column() im=None for image in bpy.data.images: if image.name == self.image: im=image split = column.split(factor=0.8,align=True) split.prop_search(self,"image",context.blend_data,"images",text="") split.operator("pov.imageopen",text="",icon="FILEBROWSER") if im is not None: column.prop(im,"source",text="") column.prop(self,"map_type",text="") column.prop(self,"interpolate",text="") row=column.row() row.prop(self,"premultiplied",text="Premul") row.prop(self,"once",text="Once") def draw_buttons_ext(self, context, layout): column=layout.column() im=None for image in bpy.data.images: if image.name == self.image: im=image split = column.split(factor=0.8,align=True) split.prop_search(self,"image",context.blend_data,"images",text="") split.operator("pov.imageopen",text="",icon="FILEBROWSER") if im is not None: column.prop(im,"source",text="") column.prop(self,"map_type",text="") column.prop(self,"interpolate",text="") row=column.row() row.prop(self,"premultiplied",text="Premul") row.prop(self,"once",text="Once") def draw_label(self): return "Image map" class PovrayBumpMapNode(Node, ObjectNodeTree): '''BumpMap''' bl_idname = 'PovrayBumpMapNode' bl_label = 'Bump map' bl_icon = 'SOUND' map_type : bpy.props.EnumProperty( name="Map type", description="", items=( ('uv_mapping', "UV", ""), ('0', "Planar", "Default planar mapping"), ('1', "Spherical", "Spherical mapping"), ('2', "Cylindrical", "Cylindrical mapping"), ('5', "Torroidal", "Torus or donut shaped mapping") ), default='0') image : StringProperty(maxlen=1024) # , subtype="FILE_PATH" interpolate : EnumProperty( name="Interpolate", description="Adding the interpolate keyword can smooth the jagged look of a bitmap", items=( ('2', "Bilinear", "Gives bilinear interpolation"), ('4', "Normalized", "Gives normalized distance"), ), default='2') once : BoolProperty(description="Not to repeat", default=False) def init(self, context): self.inputs.new('PovraySocketFloat_0_10', "Normal") mapping=self.inputs.new('NodeSocketVector', "Mapping") mapping.hide_value=True transform=self.inputs.new('NodeSocketVector', "Transform") transform.hide_value=True modifier=self.inputs.new('NodeSocketVector', "Modifier") modifier.hide_value=True normal=self.outputs.new('NodeSocketFloat', "Normal") normal.hide_value=True def draw_buttons(self, context, layout): column=layout.column() im=None for image in bpy.data.images: if image.name == self.image: im=image split = column.split(percentage=0.8,align=True) split.prop_search(self,"image",context.blend_data,"images",text="") split.operator("pov.imageopen",text="",icon="FILEBROWSER") if im is not None: column.prop(im,"source",text="") column.prop(self,"map_type",text="") column.prop(self,"interpolate",text="") column.prop(self,"once",text="Once") def draw_buttons_ext(self, context, layout): column=layout.column() im=None for image in bpy.data.images: if image.name == self.image: im=image split = column.split(percentage=0.8,align=True) split.prop_search(self,"image",context.blend_data,"images",text="") split.operator("pov.imageopen",text="",icon="FILEBROWSER") if im is not None: column.prop(im,"source",text="") column.prop(self,"map_type",text="") column.prop(self,"interpolate",text="") column.prop(self,"once",text="Once") def draw_label(self): return "Bump Map" class PovrayImagePatternNode(Node, ObjectNodeTree): '''ImagePattern''' bl_idname = 'PovrayImagePatternNode' bl_label = 'Image pattern' bl_icon = 'SOUND' map_type: bpy.props.EnumProperty( name="Map type", description="", items=( ('uv_mapping', "UV", ""), ('0', "Planar", "Default planar mapping"), ('1', "Spherical", "Spherical mapping"), ('2', "Cylindrical", "Cylindrical mapping"), ('5', "Torroidal", "Torus or donut shaped mapping"), ), default='0') image: StringProperty(maxlen=1024) # , subtype="FILE_PATH" interpolate: EnumProperty( name="Interpolate", description="Adding the interpolate keyword can smooth the jagged look of a bitmap", items=( ('2', "Bilinear", "Gives bilinear interpolation"), ('4', "Normalized", "Gives normalized distance"), ), default='2') premultiplied: BoolProperty(default=False) once: BoolProperty(description="Not to repeat", default=False) use_alpha: BoolProperty(default=True) def init(self, context): gamma=self.inputs.new('PovraySocketFloat_000001_10', "Gamma") gamma.default_value=2.0 self.outputs.new('PovraySocketPattern', "Pattern") def draw_buttons(self, context, layout): column=layout.column() im=None for image in bpy.data.images: if image.name == self.image: im=image split = column.split(factor=0.8,align=True) split.prop_search(self,"image",context.blend_data,"images",text="") split.operator("pov.imageopen",text="",icon="FILEBROWSER") if im is not None: column.prop(im,"source",text="") column.prop(self,"map_type",text="") column.prop(self,"interpolate",text="") row=column.row() row.prop(self,"premultiplied",text="Premul") row.prop(self,"once",text="Once") column.prop(self,"use_alpha",text="Use alpha") def draw_buttons_ext(self, context, layout): column=layout.column() im=None for image in bpy.data.images: if image.name == self.image: im=image split = column.split(factor=0.8,align=True) split.prop_search(self,"image",context.blend_data,"images",text="") split.operator("pov.imageopen",text="",icon="FILEBROWSER") if im is not None: column.prop(im,"source",text="") column.prop(self,"map_type",text="") column.prop(self,"interpolate",text="") row=column.row() row.prop(self,"premultiplied",text="Premul") row.prop(self,"once",text="Once") def draw_label(self): return "Image pattern" class ShaderPatternNode(Node, ObjectNodeTree): '''Pattern''' bl_idname = 'ShaderPatternNode' bl_label = 'Other patterns' pattern : EnumProperty( name="Pattern", description="Agate, Crackle, Gradient, Pavement, Spiral, Tiling", items=(('agate', "Agate", ""),('crackle', "Crackle", ""),('gradient', "Gradient", ""), ('pavement', "Pavement", ""), ('spiral1', "Spiral 1", ""), ('spiral2', "Spiral 2", ""), ('tiling', "Tiling", "")), default='agate') agate_turb : FloatProperty( name="Agate turb", description="Agate turbulence", min=0.0, max=100.0, default=0.5) crackle_form_x : FloatProperty( name="X", description="Form vector X", min=-150.0, max=150.0, default=-1) crackle_form_y : FloatProperty( name="Y", description="Form vector Y", min=-150.0, max=150.0, default=1) crackle_form_z : FloatProperty( name="Z", description="Form vector Z", min=-150.0, max=150.0, default=0) crackle_metric : FloatProperty( name="Metric", description="Crackle metric", min=0.0, max=150.0, default=1) crackle_solid : BoolProperty( name="Solid", description="Crackle solid", default=False) spiral_arms : FloatProperty( name="Number", description="", min=0.0, max=256.0, default=2.0) tiling_number : IntProperty( name="Number", description="", min=1, max=27, default=1) gradient_orient : EnumProperty( name="Orient", description="", items=(('x', "X", ""), ('y', "Y", ""), ('z', "Z", "")), default='x') def init(self, context): pat = self.outputs.new('PovraySocketPattern', "Pattern") def draw_buttons(self, context, layout): layout.prop(self, "pattern",text="") if self.pattern=='agate': layout.prop(self, "agate_turb") if self.pattern=='crackle': layout.prop(self, "crackle_metric") layout.prop(self, "crackle_solid") layout.label(text="Form:") layout.prop(self, "crackle_form_x") layout.prop(self, "crackle_form_y") layout.prop(self, "crackle_form_z") if self.pattern in {"spiral1","spiral2"}: layout.prop(self, "spiral_arms") if self.pattern in {'tiling'}: layout.prop(self, "tiling_number") if self.pattern in {'gradient'}: layout.prop(self, "gradient_orient") def draw_buttons_ext(self, context, layout): pass def draw_label(self): return "Other patterns" class ShaderTextureMapNode(Node, ObjectNodeTree): '''Texture Map''' bl_idname = 'ShaderTextureMapNode' bl_label = 'Texture map' brick_size_x: FloatProperty( name="X", description="", min=0.0000, max=1.0000, default=0.2500) brick_size_y: FloatProperty( name="Y", description="", min=0.0000, max=1.0000, default=0.0525) brick_size_z: FloatProperty( name="Z", description="", min=0.0000, max=1.0000, default=0.1250) brick_mortar: FloatProperty( name="Mortar", description="Mortar", min=0.000, max=1.500, default=0.01) def init(self, context): mat = bpy.context.object.active_material self.inputs.new('PovraySocketPattern', "") color = self.inputs.new('NodeSocketColor', "Color ramp") color.hide_value = True for i in range(0,4): transform=self.inputs.new('PovraySocketTransform', "Transform") transform.hide_value=True number = mat.pov.inputs_number for i in range(number): self.inputs.new('PovraySocketTexture', "%s"%i) self.outputs.new('PovraySocketTexture', "Texture") def draw_buttons(self, context, layout): if self.inputs[0].default_value =='brick': layout.prop(self, "brick_mortar") layout.label(text="Brick size:") layout.prop(self, "brick_size_x") layout.prop(self, "brick_size_y") layout.prop(self, "brick_size_z") def draw_buttons_ext(self, context, layout): if self.inputs[0].default_value =='brick': layout.prop(self, "brick_mortar") layout.label(text="Brick size:") layout.prop(self, "brick_size_x") layout.prop(self, "brick_size_y") layout.prop(self, "brick_size_z") def draw_label(self): return "Texture map" class ShaderNormalMapNode(Node, ObjectNodeTree): '''Normal Map''' bl_idname = 'ShaderNormalMapNode' bl_label = 'Normal map' brick_size_x : FloatProperty( name="X", description="", min=0.0000, max=1.0000, default=0.2500) brick_size_y : FloatProperty( name="Y", description="", min=0.0000, max=1.0000, default=0.0525) brick_size_z : FloatProperty( name="Z", description="", min=0.0000, max=1.0000, default=0.1250) brick_mortar : FloatProperty( name="Mortar", description="Mortar", min=0.000, max=1.500, default=0.01) def init(self, context): self.inputs.new('PovraySocketPattern', "") normal = self.inputs.new('PovraySocketFloat_10', "Normal") slope = self.inputs.new('PovraySocketMap', "Slope map") for i in range(0,4): transform=self.inputs.new('PovraySocketTransform', "Transform") transform.hide_value=True self.outputs.new('PovraySocketNormal', "Normal") def draw_buttons(self, context, layout): #for i, inp in enumerate(self.inputs): if self.inputs[0].default_value =='brick': layout.prop(self, "brick_mortar") layout.label(text="Brick size:") layout.prop(self, "brick_size_x") layout.prop(self, "brick_size_y") layout.prop(self, "brick_size_z") def draw_buttons_ext(self, context, layout): if self.inputs[0].default_value =='brick': layout.prop(self, "brick_mortar") layout.label(text="Brick size:") layout.prop(self, "brick_size_x") layout.prop(self, "brick_size_y") layout.prop(self, "brick_size_z") def draw_label(self): return "Normal map" class ShaderNormalMapEntryNode(Node, ObjectNodeTree): '''Normal Map Entry''' bl_idname = 'ShaderNormalMapEntryNode' bl_label = 'Normal map entry' def init(self, context): self.inputs.new('PovraySocketFloat_0_1', "Stop") self.inputs.new('PovraySocketFloat_0_1', "Gray") def draw_label(self): return "Normal map entry" class IsoPropsNode(Node, CompositorNodeTree): '''ISO Props''' bl_idname = 'IsoPropsNode' bl_label = 'Iso' node_label : StringProperty(maxlen=1024) def init(self, context): ob = bpy.context.object self.node_label = ob.name textName = ob.pov.function_text if textName: text = bpy.data.texts[textName] for line in text.lines: split = line.body.split() if split[0] == "#declare": socket = self.inputs.new('NodeSocketFloat', "%s"%split[1]) value = split[3].split(";") value = value[0] socket.default_value=float(value) def draw_label(self): return self.node_label class PovrayFogNode(Node, CompositorNodeTree): '''Fog settings''' bl_idname = 'PovrayFogNode' bl_label = 'Fog' def init(self, context): color=self.inputs.new('NodeSocketColor', "Color") color.default_value=(0.7,0.7,0.7,0.25) self.inputs.new('PovraySocketFloat_0_1', "Filter") distance = self.inputs.new('NodeSocketInt', "Distance") distance.default_value=150 self.inputs.new('NodeSocketBool', "Ground") fog_offset=self.inputs.new('NodeSocketFloat', "Offset") fog_alt=self.inputs.new('NodeSocketFloat', "Altitude") turb = self.inputs.new('NodeSocketVector', "Turbulence") turb_depth=self.inputs.new('PovraySocketFloat_0_10', "Depth") turb_depth.default_value=0.5 octaves=self.inputs.new('PovraySocketInt_1_9', "Octaves") octaves.default_value=5 lambdat=self.inputs.new('PovraySocketFloat_0_10', "Lambda") lambdat.default_value=1.25 omega=self.inputs.new('PovraySocketFloat_0_10', "Omega") omega.default_value=0.35 translate = self.inputs.new('NodeSocketVector', "Translate") rotate = self.inputs.new('NodeSocketVector', "Rotate") scale = self.inputs.new('NodeSocketVector', "Scale") scale.default_value=(1,1,1) def draw_label(self): return "Fog" class PovraySlopeNode(Node, TextureNodeTree): '''Output''' bl_idname = 'PovraySlopeNode' bl_label = 'Slope Map' def init(self, context): self.use_custom_color = True self.color = (0,0.2,0) slope = self.inputs.new('PovraySocketSlope', "0") slope = self.inputs.new('PovraySocketSlope', "1") slopemap = self.outputs.new('PovraySocketMap', "Slope map") output.hide_value = True def draw_buttons(self, context, layout): layout.operator("pov.nodeinputadd") row = layout.row() row.label(text='Value') row.label(text='Height') row.label(text='Slope') def draw_buttons_ext(self, context, layout): layout.operator("pov.nodeinputadd") row = layout.row() row.label(text='Value') row.label(text='Height') row.label(text='Slope') def draw_label(self): return "Slope Map" ######################################## Texture nodes ############################### class TextureOutputNode(Node, TextureNodeTree): '''Output''' bl_idname = 'TextureOutputNode' bl_label = 'Color Map' def init(self, context): tex = bpy.context.object.active_material.active_texture num_sockets = int(tex.pov.density_lines/32) for i in range(num_sockets): color = self.inputs.new('NodeSocketColor', "%s"%i) color.hide_value = True def draw_buttons(self, context, layout): layout.label(text="Color Ramps:") def draw_label(self): return "Color Map" ################################################################################## #################################Operators######################################## ################################################################################## class NODE_OT_iso_add(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 # view_layer = context.view_layer # view_layer.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.view_layer ob=context.object for obj in scene.objects: if obj != ob: scene.objects.active = ob break scene.objects.active = ob def modal(self, context, event): if event.type == 'RIGHTMOUSE': self.execute(context) return {'FINISHED'} return {'PASS_THROUGH'} def invoke(self, context, event): context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} class UpdatePreviewKey(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'} classes = ( ObjectNodeTree, PovrayOutputNode, PovrayTextureNode, PovrayFinishNode, PovrayDiffuseNode, PovrayPhongNode, PovraySpecularNode, PovrayMirrorNode, PovrayAmbientNode, PovrayIridescenceNode, PovraySubsurfaceNode, PovrayMappingNode, PovrayMultiplyNode, PovrayTransformNode, PovrayValueNode, PovrayModifierNode, PovrayPigmentNode, PovrayColorImageNode, PovrayBumpMapNode, PovrayImagePatternNode, ShaderPatternNode, ShaderTextureMapNode, ShaderNormalMapNode, ShaderNormalMapEntryNode, IsoPropsNode, PovrayFogNode, PovraySlopeNode, TextureOutputNode, NODE_OT_iso_add, NODE_OT_map_create, NODE_OT_povray_node_texture_map_add, NODE_OT_povray_node_output_add, NODE_OT_povray_node_layered_add, NODE_OT_povray_input_add, NODE_OT_povray_input_remove, NODE_OT_povray_image_open, PovrayPatternNode, UpdatePreviewMaterial, UpdatePreviewKey, ) def register(): #from bpy.utils import register_class for cls in classes: register_class(cls) def unregister(): from bpy.utils import unregister_class for cls in classes: unregister_class(cls)