import bpy, bmesh
from . utility import addon
from bpy.types import PropertyGroup, Operator
from bpy.props import EnumProperty, StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty
from .operators.modals.material_scroll import random_principled
import random
class HopsMaterialOptions(PropertyGroup):
material_mode: EnumProperty(
name = 'Mode',
items = [
('ALL', 'All', 'Look for all materials'),
('OBJECT', 'Object', 'Look for materials on the active object'),
('BLANK', 'Blank', 'Create new material on each cut')],
default = 'ALL')
active_material: StringProperty(
name = 'Select Material',
description = 'Assign the secondary material for bool operations',
default = '')
force: BoolProperty(
name = 'Force',
description = 'Force this material as the only material for cutting objects',
default = True)
color_prob: FloatProperty(
name = 'Color Probability',
description = 'Color Probability',
default = 0.0,
min = 0,
max =1)
def blank_cutting_mat ():
option = bpy.context.window_manager.Hard_Ops_material_options
mat_name = random_principled(color_prob=option.color_prob).name
option.active_material = mat_name
def get_active_material(context):
option = context.window_manager.Hard_Ops_material_options
if option.material_mode == 'BLANK':
blank_cutting_mat()
return bpy.data.materials.get(option.active_material, None)
def assign_material(context, obj, replace=False, csplit=False):
option = context.window_manager.Hard_Ops_material_options
if option.material_mode == 'BLANK':
blank_cutting_mat()
if option.active_material:
if obj:
if replace:
obj.data.materials.clear()
obj.data.materials.append(bpy.data.materials[option.active_material])
else:
prepare(context, option, obj)
if not csplit:
add_material(context, context.active_object, bpy.data.materials[option.active_material])
def prepare(context, option, obj):
if option.force:
obj.data.materials.clear()
obj.data.materials.append(bpy.data.materials[option.active_material])
def add_material(context, obj, mat=None, option=None):
if not mat and option:
mat = bpy.materials[option.active_material]
elif not mat:
mat = bpy.data.materials.new("Material")
if mat not in [s.material for s in obj.material_slots]:
obj.data.materials.append(mat)
return mat
def add(context, obj, mat=None, mats=[], append=True, viewport=False, view_grayscale=False, view_alpha=False):
if not append and obj.mode != 'EDIT':
obj.data.materials.clear()
if mat:
obj.data.materials.append(mat)
index = len(obj.data.materials) -1
obj.active_material_index = index
if obj.mode == 'EDIT':
bm = bmesh.from_edit_mesh(obj.data)
for f in bm.faces:
if f.select:
f.material_index = index
bmesh.update_edit_mesh(obj.data)
if viewport:
mat.diffuse_color = random_color(view_alpha, view_grayscale)
elif mats:
for mat in mats:
obj.data.materials.append(mat)
if viewport:
mat.diffuse_color = random_color(view_alpha, view_grayscale)
obj.active_material_index = len(obj.data.materials) -1
else:
mat = add_material(context, obj)
if viewport:
mat.diffuse_color = random_color(1.0 if view_alpha else False, view_grayscale)
def clamp_value(value, clamp_min=0.0, clamp_max=1.0):
return max(min(value, clamp_max), clamp_min)
def random_color(alpha=False, grayscale=False, clamp=False, clamp_min=0.0, clamp_max=0.10):
color = [0,0,0]
if not grayscale:
color[0] = random.randint(1000, 8000) * 0.0001
color[1] = random.randint(1000, 8000) * 0.0001
color[2] = random.randint(1000, 8000) * 0.0001
else:
value = random.randint(100, 4000) * 0.0001
color[0] = value
color[1] = value
color[2] = value
if clamp:
color[0] = clamp_value(color[0], clamp_min, clamp_max)
color[1] = clamp_value(color[1], clamp_min, clamp_max)
color[2] = clamp_value(color[2], clamp_min, clamp_max)
return (*color, random.randint(1000, 9000) * 0.0001 if alpha else 1.0)
class MATERIAL_OT_hops_new(Operator):
bl_idname = 'material.hops_new'
bl_label = 'Blank Material'
bl_description = '''Add a new blank random material
Ctrl - Unique Material per object
Shift - Glass Material per object
Alt - Pulsing Emissive Material per object
Ctrl + Shift - UV Material
'''
bl_options = {'REGISTER', 'UNDO'}
type: EnumProperty(
name = 'Type',
description = 'Material type',
items = [
('PRINCIPLED', 'Principled', ''),
('GLASS', 'Glass', ''),
('EMISSION', 'Emission', ''),
('CARPAINT', 'CarPaint', ''),
('GENERAL', 'General', ''),
('UV', 'UV', ''),
],
default = 'PRINCIPLED',
)
unique: BoolProperty(
name = 'Unique Material',
description = 'Give unique material per object',
default = False,
)
pulse: BoolProperty(
name = 'Pulse',
description = 'Give a pulsing material',
default = True,
)
frequency: FloatProperty(
name = 'Frequency',
description = 'Control pulse frequency',
min = 0.01,
soft_max = 2.0,
default = 1.0,
)
grayscale: BoolProperty(
name = 'grayscale',
description = 'Randomize values and not color',
default = True,
)
colorize: BoolProperty(
name = 'colorize',
description = 'Mix an RGB Color in for varying shades of color',
default = False,
)
clearcoat: BoolProperty(
name = 'clearcoat',
description = "Whether or not to have random clearcoats included",
default = False,
)
colorize_rgb: FloatVectorProperty(
name = 'colorize_rgb',
description = 'RGB Color to mixin for colorize',
size = 4,
min = 0,
max = 1,
subtype='COLOR',
default = (0.785, 0.276225, 0.123828, 1.0),
)
clamp: BoolProperty(
name = 'Clamp',
description = 'Clamp Min/Max Grayscale Values',
default = True,
)
clamp_expand: BoolProperty(
name = 'Expand Clamp',
description = 'Expand Advanced Clamp Options',
default = False,
)
clamp_min_nonmetals: FloatProperty(
name = 'Min Clamp Value (non-metals)',
description = 'Minimum Clamp Value for non-metals',
min = 0.0,
soft_max = 1.0,
default = 0.0,
)
clamp_max_nonmetals: FloatProperty(
name = 'Max Clamp Value (non-metals)',
description = 'Maximum Clamp Value for non-metals',
min = 0.0,
soft_max = 1.0,
default = 0.10,
)
clamp_min_metals: FloatProperty(
name = 'Min Clamp Value (metals)',
description = 'Minimum Clamp Value for metals',
min = 0.0,
soft_max = 1.0,
default = 0.0,
)
clamp_max_metals: FloatProperty(
name = 'Max Clamp Value (metals)',
description = 'Maximum Clamp Value for metals',
min = 0.0,
soft_max = 1.0,
default = 0.50,
)
### BEGIN rampbased variables
rampbased_ramp_start: FloatVectorProperty(
name = 'rampbased_ramp_start',
description = 'RGB Color to Start Ramp at',
size = 4,
min = 0,
max = 1,
subtype='COLOR',
default = (0.03, 0.03, 0.03, 1.0),
)
rampbased_ramp_end: FloatVectorProperty(
name = 'rampbased_ramp_end',
description = 'RGB Color to End Ramp at',
size = 4,
min = 0,
max = 1,
subtype='COLOR',
default = (0.25, 0.25, 0.25, 1.0),
)
rampbased_ramp_spread: FloatProperty(
name = 'rampbased_ramp_spread',
description = 'Ramp Spread Distance',
min = 0.0,
soft_max = 1.0,
default = 0.4,
)
rampbased_roughness_min: FloatProperty(
name = 'rampbased_roughness_min',
description = 'Minimum roughness',
min = 0.0,
max = 1.0,
default = 0.15,
)
rampbased_roughness_max: FloatProperty(
name = 'rampbased_roughness_max',
description = 'Maximum roughness',
min = 0.0,
max = 1.0,
default = 0.40,
)
rampbased_metal_probability: FloatProperty(
name = 'rampbased_metal_probability',
description = 'Metal Probability',
min = 0.0,
max = 100.0,
default = 85.0,
subtype = 'PERCENTAGE',
)
rampbased_clearcoat_probability: FloatProperty(
name = 'rampbased_metal_probability',
description = 'Clearcoat Probability',
min = 0.0,
max = 100.0,
default = 20.0,
subtype = 'PERCENTAGE',
)
rampbased_carpaint_probability: FloatProperty(
name = 'rampbased_carpaint_probability',
description = 'Car Paint Probability',
min = 0.0,
max = 100.0,
default = 0.0,
subtype = 'PERCENTAGE',
)
rampbased_carpaint_metallic: BoolProperty(
name = 'rampbased_carpaint_metallic',
description = 'Carpaint Metallic',
default = True,
)
carpaint_hue_shift: FloatProperty(
name = 'carpaint_hue_shift',
description = 'Car Paint Hue Shift',
min = 0.0,
max = 1.0,
default = 0.8,
)
carpaint_hue_variation: FloatProperty(
name = 'carpaint_hue_variation',
description = 'Carpaint Hue Variation',
min = 0.0,
max = 100.0,
default = 0.0,
subtype = 'PERCENTAGE',
)
carpaint_saturation: FloatProperty(
name = 'carpaint_saturation',
description = 'Carpaint Saturation',
min = 0.0,
max = 1.0,
default = 1.0,
)
carpaint_value_brightness: FloatProperty(
name = 'carpaint_value_brightness',
description = 'Carpaint Brightness',
min = 0.0,
max = 1.0,
default = 0.3,
)
carpaint_expand_advanced: BoolProperty(
name = 'carpaint_expand_advanced',
description = 'Expand Advanced Carpaint Options',
default = False,
)
carpaint_colorramp_start_color: FloatVectorProperty(
name = 'carpaint_colorramp_start_color',
description = 'RGB Color to start Carpaint Ramp',
size = 4,
min = 0,
max = 1,
subtype='COLOR',
default = (0.553429, 0.151442, 0.051457, 1.000000),
)
carpaint_colorramp_end_color: FloatVectorProperty(
name = 'carpaint_colorramp_end_color',
description = 'RGB Color to end Carpaint Ramp',
size = 4,
min = 0,
max = 1,
subtype='COLOR',
default = (1.000000, 0.023302, 0.014752, 1.000000),
)
carpaint_roughness_scale: FloatProperty(
name = 'carpaint_roughness_scale',
description = 'Car Paint Roughness Scale',
min = 0.0,
max = 30000.0,
default = 4000.0,
)
carpaint_roughness_ramp_start: FloatVectorProperty(
name = 'carpaint_roughness_ramp_start',
description = 'Carpaint Roughness Start',
size = 4,
min = 0,
max = 1,
subtype='COLOR',
default = (0.05, 0.05, 0.05, 1.000000),
)
carpaint_roughness_ramp_end: FloatVectorProperty(
name = 'carpaint_roughness_ramp_end',
description = 'Carpaint Roughness Start',
size = 4,
min = 0,
max = 1,
subtype='COLOR',
default = (0.75, 0.75, 0.75, 1.000000),
)
### END rampbased variables
cleanup: BoolProperty(
name = 'Remove Zero User Materials',
description = 'Remove Zero User Materials',
default = True,
)
helper_call: BoolProperty(
name = 'Call from HOPS helper',
description = 'Internal helper',
default = False,
)
bevel_shader: BoolProperty(
name = 'Bevel Shader',
description = 'Add Bevel Shader node. Requires Cycles to do anything',
default = False,
)
bevel_shader_radius: FloatProperty(
name = 'Radius',
description = 'Radius value. Or whatever it means to blender',
default = 0.015,
)
bevel_shader_samples: IntProperty(
name = 'Samples',
description = 'Number of samples ',
default =4,
)
active_only: BoolProperty(
name = 'Active Only',
description = 'Only affect active material slot',
default = False,
)
uv_texture: EnumProperty(
name = 'Texture',
description = 'Texture Type',
items = [
('COLOR_GRID', 'Color Grid', ''),
('UV_GRID', 'UV Grid', ''),
],
default = 'COLOR_GRID',
)
@staticmethod
def new(name='Material', blend_method='OPAQUE'):
mat = bpy.data.materials.new(name=name)
mat.use_nodes = True
mat.blend_method = blend_method
return mat
@staticmethod
def new_node(tree, x=300, y=300, bl_idname='ShaderNodeOutputMaterial'):
new = tree.nodes.new(type=bl_idname)
new.location.x = x
new.location.y = y
return new
# return tree.nodes.new(type=bl_idname)
@staticmethod
def node(tree, bl_idname='ShaderNodeOutputMaterial', index=-1, name=None):
nodes = [node for node in tree.nodes if node.bl_idname == bl_idname]
if name:
for node in nodes:
if node.name == name:
return node
node = nodes[index] if nodes else None
return node
@staticmethod
def socket(node, type='outputs', socket_type='SHADER', index=0, path_id=''):
socket = [socket for socket in getattr(node, type) if socket.type == socket_type][index]
if not path_id:
return socket
else:
return socket.path_from_id(path_id)
def socket_connect(self, tree, node_from, node_to, index_from=0, index_to=0, socket_type='SHADER', socket_to_type=''):
socket_out = self.socket(node_from, socket_type=socket_type, index=index_from)
socket_in = self.socket(node_to, type='inputs', socket_type=socket_type if not socket_to_type else socket_to_type, index=index_to)
tree.links.new(socket_out, socket_in)
def connected_nodes(self, node, nodes):
if not node:
return []
for socket in node.inputs:
if socket.is_linked:
self.connected_nodes(socket.links[0].from_node, nodes)
if node not in nodes:
nodes.append(node)
return nodes
def principled(self, mat, clear=True):
tree = mat.node_tree
output = self.node(tree)
principled = self.node(tree, bl_idname='ShaderNodeBsdfPrincipled')
rgb_picker = self.node(tree, bl_idname='ShaderNodeRGB')
rgb_mix_node = self.node(tree, bl_idname='ShaderNodeMixRGB')
if not principled:
principled = self.new_node(tree,
bl_idname = 'ShaderNodeBsdfPrincipled',
x = output.location.x-180,
y = output.location.y)
self.socket_connect(tree, principled, output)
if self.colorize:
if not rgb_mix_node:
rgb_mix_node = self.new_node(tree,
bl_idname = 'ShaderNodeMixRGB',
x = output.location.x-460,
y = output.location.y,
)
self.socket_connect(tree, rgb_mix_node, principled, socket_type='RGBA')
if not rgb_picker:
rgb_picker = self.new_node(
tree,
bl_idname = 'ShaderNodeRGB',
x = output.location.x-620,
y = output.location.y,
)
rgb_picker.outputs[0].default_value = self.colorize_rgb
self.socket_connect(tree, rgb_picker, rgb_mix_node, socket_type='RGBA')
if not clear:
metallic = principled.inputs['Metallic']
metallic.default_value = round(random.uniform(0.45, 0.99), 0)
color = principled.inputs['Base Color']
if self.clamp:
if metallic.default_value == 1.0:
tmp_clamp_min = self.clamp_min_metals
tmp_clamp_max = self.clamp_max_metals
else:
tmp_clamp_min = self.clamp_min_nonmetals
tmp_clamp_max = self.clamp_max_nonmetals
color.default_value = random_color(
grayscale=self.grayscale,
clamp=self.clamp,
clamp_min=tmp_clamp_min,
clamp_max=tmp_clamp_max,
)
else:
color.default_value = random_color(
grayscale=self.grayscale,
clamp=self.clamp,
)
if self.colorize:
# here we set the random grayscale in the mixRGB Color2
rgb_mix_node.inputs['Color2'].default_value = color.default_value
roughness = principled.inputs['Roughness']
roughness.default_value = random.uniform(0.01, 0.4)
if bpy.app.version[0] < 4:
clearcoat = principled.inputs['Clearcoat']
else:
clearcoat = principled.inputs['Coat Weight']
if self.clearcoat:
clearcoat.default_value = random.randint(0, 1)
else:
clearcoat.default_value = 0
if self.bevel_shader:
bevel = tree.nodes.new('ShaderNodeBevel')
bevel.location = (-170, -170)
bevel.samples = self.bevel_shader_samples
bevel.inputs['Radius'].default_value = self.bevel_shader_radius
tree.links.new(bevel.outputs[0], principled.inputs['Normal'])
mat.diffuse_color = color.default_value if not color.is_linked else rgb_picker.outputs[0].default_value
return
if principled:
tree.nodes.remove(principled)
def carpaint(self, mat, clear=True):
tree = mat.node_tree
output = self.node(tree)
principled_carpaint = self.node(tree, bl_idname='ShaderNodeBsdfPrincipled')
carpaint_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='carpaint_ramp')
carpaint_rgb_to_bw = self.node(tree, bl_idname='ShaderNodeRGBToBW', name='carpaint_rgb_to_bw')
carpaint_round = self.node(tree, bl_idname='ShaderNodeMath', name='carpaint_round')
carpaint_hsv = self.node(tree, bl_idname='ShaderNodeHueSaturation', name='carpaint_hsv')
carpaint_shift_mix = self.node(tree, bl_idname='ShaderNodeMixRGB', name='carpaint_shift_mix')
carpaint_shift_value = self.node(tree, bl_idname='ShaderNodeValue', name='carpaint_shift_value')
carpaint_shift_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='carpaint_shift_ramp')
object_info = self.node(tree, bl_idname='ShaderNodeObjectInfo', name='object_info')
carpaint_colorramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='carpaint_colorramp')
carpaint_layerweight = self.node(tree, bl_idname='ShaderNodeLayerWeight', name='carpaint_layerweight')
carpaint_roughness_rgb_to_bw = self.node(tree, bl_idname='ShaderNodeRGBToBW', name='carpaint_roughness_rgb_to_bw')
carpaint_roughness_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='carpaint_roughness_ramp')
carpaint_roughness_voronoi = self.node(tree, bl_idname='ShaderNodeTexVoronoi', name='carpaint_roughness_voronoi')
tex_coord = self.node(tree, bl_idname='ShaderNodeTexCoord', name='tex_coord')
carpaint_metallic_value = self.node(tree, bl_idname='ShaderNodeValue', name='carpaint_metallic_value')
self.carpaint_hue_shift = random.uniform(0,1)
if not clear:
# CARPAINT BEGIN
if not principled_carpaint:
principled_carpaint = self.new_node(
tree,
bl_idname = 'ShaderNodeBsdfPrincipled',
x = output.location.x,
y = output.location.y-400,
)
principled_carpaint.name = 'principled_carpaint'
principled_carpaint.label = 'principled_carpaint'
self.socket_connect(tree, principled_carpaint, output, 0, 0, socket_type='SHADER')
if bpy.app.version[0] < 4:
principled_carpaint.inputs['Clearcoat'].default_value = 1.0 # set clearcoat
principled_carpaint.inputs['Clearcoat'].default_value = 0.05 # set clearcoat roughness
else:
principled_carpaint.inputs['Coat Weight'].default_value = 1.0 # set clearcoat
principled_carpaint.inputs['Coat Roughness'].default_value = 0.05 # set clearcoat roughness
if not carpaint_metallic_value:
carpaint_metallic_value = self.new_node(
tree,
bl_idname = 'ShaderNodeValue',
x = principled_carpaint.location.x-275,
y = principled_carpaint.location.y-300,
)
carpaint_metallic_value.name = 'carpaint_metallic_value'
carpaint_metallic_value.label = 'carpaint_metallic_value'
self.socket_connect(tree, carpaint_metallic_value, principled_carpaint, 0, 1, socket_type='VALUE')
if self.rampbased_carpaint_metallic:
carpaint_metallic_value.outputs[0].default_value = 1.0
else:
carpaint_metallic_value.outputs[0].default_value = 0.0
if not carpaint_hsv:
carpaint_hsv = self.new_node(
tree,
bl_idname = 'ShaderNodeHueSaturation',
x = principled_carpaint.location.x-275,
y = principled_carpaint.location.y,
)
carpaint_hsv.name = 'carpaint_hsv'
carpaint_hsv.label = 'carpaint_hsv'
self.socket_connect(tree, carpaint_hsv, principled_carpaint, 0, 0, socket_type='RGBA')
carpaint_hsv.inputs['Hue'].default_value = self.carpaint_hue_shift
carpaint_hsv.inputs['Saturation'].default_value = self.carpaint_saturation
carpaint_hsv.inputs['Value'].default_value = self.carpaint_value_brightness
if not carpaint_shift_mix:
carpaint_shift_mix = self.new_node(
tree,
bl_idname = 'ShaderNodeMixRGB',
x = carpaint_hsv.location.x-275,
y = carpaint_hsv.location.y-300,
)
carpaint_shift_mix.name = 'carpaint_shift_mix'
carpaint_shift_mix.label = 'carpaint_shift_mix'
self.socket_connect(tree, carpaint_shift_mix, carpaint_hsv, 0, 0, socket_type='RGBA', socket_to_type='VALUE')
carpaint_shift_mix.inputs['Fac'].default_value = self.carpaint_hue_variation / 100.0
if not carpaint_shift_value:
carpaint_shift_value = self.new_node(
tree,
bl_idname = 'ShaderNodeValue',
x = carpaint_shift_mix.location.x-275,
y = carpaint_shift_mix.location.y+100,
)
carpaint_shift_value.name = 'carpaint_shift_value'
carpaint_shift_value.label = 'carpaint_shift_value'
self.socket_connect(tree, carpaint_shift_value, carpaint_shift_mix, 0, 0, socket_type='VALUE', socket_to_type='RGBA')
carpaint_shift_value.outputs[0].default_value = self.carpaint_hue_shift
if not carpaint_shift_ramp:
carpaint_shift_ramp = self.new_node(
tree,
bl_idname = 'ShaderNodeValToRGB',
x = carpaint_shift_value.location.x-275,
y = carpaint_shift_value.location.y-100,
)
carpaint_shift_ramp.name = 'carpaint_shift_ramp'
carpaint_shift_ramp.label = 'carpaint_shift_ramp'
self.socket_connect(tree, carpaint_shift_ramp, carpaint_shift_mix, 0, 1, socket_type='RGBA')
if not object_info:
object_info = self.new_node(
tree,
bl_idname = 'ShaderNodeObjectInfo',
x = carpaint_shift_ramp.location.x-250,
y = carpaint_shift_ramp.location.y,
)
object_info.name = 'object_info'
object_info.label = 'object_info'
self.socket_connect(tree, object_info, carpaint_shift_ramp, 2, 0, socket_type='VALUE')
if not carpaint_colorramp:
carpaint_colorramp = self.new_node(
tree,
bl_idname = 'ShaderNodeValToRGB',
x = carpaint_hsv.location.x-275,
y = carpaint_hsv.location.y,
)
carpaint_colorramp.name = 'carpaint_colorramp'
carpaint_colorramp.label = 'carpaint_colorramp'
self.socket_connect(tree, carpaint_colorramp, carpaint_hsv, 0, 0, socket_type='RGBA')
carpaint_colorramp.color_ramp.elements[0].color = self.carpaint_colorramp_start_color
carpaint_colorramp.color_ramp.elements[1].color = self.carpaint_colorramp_end_color
carpaint_colorramp.color_ramp.elements[1].position = 0.80
if not carpaint_layerweight:
carpaint_layerweight = self.new_node(
tree,
bl_idname = 'ShaderNodeLayerWeight',
x = carpaint_colorramp.location.x-275,
y = carpaint_colorramp.location.y,
)
carpaint_layerweight.name = 'carpaint_layerweight'
carpaint_layerweight.label = 'carpaint_layerweight'
self.socket_connect(tree, carpaint_layerweight, carpaint_colorramp, 1, 0, socket_type='VALUE')
if not carpaint_roughness_rgb_to_bw:
carpaint_roughness_rgb_to_bw = self.new_node(
tree,
bl_idname = 'ShaderNodeRGBToBW',
x = principled_carpaint.location.x-275,
y = principled_carpaint.location.y-600,
)
carpaint_roughness_rgb_to_bw.name = 'carpaint_roughness_rgb_to_bw'
carpaint_roughness_rgb_to_bw.label = 'carpaint_roughness_rgb_to_bw'
self.socket_connect(tree, carpaint_roughness_rgb_to_bw, principled_carpaint, 0, 4, socket_type='VALUE')
if not carpaint_roughness_ramp:
carpaint_roughness_ramp = self.new_node(
tree,
bl_idname = 'ShaderNodeValToRGB',
x = carpaint_roughness_rgb_to_bw.location.x-300,
y = carpaint_roughness_rgb_to_bw.location.y,
)
carpaint_roughness_ramp.name = 'carpaint_roughness_ramp'
carpaint_roughness_ramp.label = 'carpaint_roughness_ramp'
self.socket_connect(tree, carpaint_roughness_ramp, carpaint_roughness_rgb_to_bw, 0, 0, socket_type='RGBA')
carpaint_roughness_ramp.color_ramp.elements[0].color = self.carpaint_roughness_ramp_start
carpaint_roughness_ramp.color_ramp.elements[1].color = self.carpaint_roughness_ramp_end
if not carpaint_roughness_voronoi:
carpaint_roughness_voronoi = self.new_node(
tree,
bl_idname = 'ShaderNodeTexVoronoi',
x = carpaint_roughness_ramp.location.x-300,
y = carpaint_roughness_ramp.location.y,
)
carpaint_roughness_voronoi.name = 'carpaint_roughness_voronoi'
carpaint_roughness_voronoi.label = 'carpaint_roughness_voronoi'
self.socket_connect(
tree,
carpaint_roughness_voronoi,
carpaint_roughness_ramp,
0,
0,
socket_type='RGBA',
socket_to_type='VALUE'
)
carpaint_roughness_voronoi.voronoi_dimensions = '4D'
carpaint_roughness_voronoi.feature = 'F1'
carpaint_roughness_voronoi.distance = 'EUCLIDEAN'
carpaint_roughness_voronoi.inputs['Scale'].default_value = self.carpaint_roughness_scale
if not tex_coord:
tex_coord = self.new_node(
tree,
bl_idname = 'ShaderNodeTexCoord',
x = carpaint_roughness_voronoi.location.x-300,
y = carpaint_roughness_voronoi.location.y,
)
tex_coord.name = 'tex_coord'
tex_coord.label = 'tex_coord'
self.socket_connect(tree, tex_coord, carpaint_roughness_voronoi, 3, 0, socket_type='VECTOR')
# CARPAINT END
return
if principled_carpaint:
tree.nodes.remove(principled_carpaint)
def general(self, mat, clear=True):
tree = mat.node_tree
output = self.node(tree)
final_mix_shader = self.node(tree, bl_idname='ShaderNodeMixShader', name='final_mix_shader')
principled = self.node(tree, bl_idname='ShaderNodeBsdfPrincipled')
principled_carpaint = self.node(tree, bl_idname='ShaderNodeBsdfPrincipled')
basecolor_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='basecolor_ramp')
roughness_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='roughness_ramp')
roughness_rgb_to_bw = self.node(tree, bl_idname='ShaderNodeRGBToBW', name='roughness_rgb_to_bw')
carpaint_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='carpaint_ramp')
carpaint_rgb_to_bw = self.node(tree, bl_idname='ShaderNodeRGBToBW', name='carpaint_rgb_to_bw')
carpaint_round = self.node(tree, bl_idname='ShaderNodeMath', name='carpaint_round')
carpaint_hsv = self.node(tree, bl_idname='ShaderNodeHueSaturation', name='carpaint_hsv')
carpaint_shift_mix = self.node(tree, bl_idname='ShaderNodeMixRGB', name='carpaint_shift_mix')
carpaint_shift_value = self.node(tree, bl_idname='ShaderNodeValue', name='carpaint_shift_value')
carpaint_shift_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='carpaint_shift_ramp')
carpaint_colorramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='carpaint_colorramp')
carpaint_layerweight = self.node(tree, bl_idname='ShaderNodeLayerWeight', name='carpaint_layerweight')
carpaint_roughness_rgb_to_bw = self.node(tree, bl_idname='ShaderNodeRGBToBW', name='carpaint_roughness_rgb_to_bw')
carpaint_roughness_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='carpaint_roughness_ramp')
carpaint_roughness_voronoi = self.node(tree, bl_idname='ShaderNodeTexVoronoi', name='carpaint_roughness_voronoi')
tex_coord = self.node(tree, bl_idname='ShaderNodeTexCoord', name='tex_coord')
carpaint_metallic_value = self.node(tree, bl_idname='ShaderNodeValue', name='carpaint_metallic_value')
metal_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='metal_ramp')
metal_rgb_to_bw = self.node(tree, bl_idname='ShaderNodeRGBToBW', name='metal_rgb_to_bw')
metal_round = self.node(tree, bl_idname='ShaderNodeMath', name='metal_round')
clearcoat_ramp = self.node(tree, bl_idname='ShaderNodeValToRGB', name='metal_ramp')
clearcoat_rgb_to_bw = self.node(tree, bl_idname='ShaderNodeRGBToBW', name='metal_rgb_to_bw')
clearcoat_round = self.node(tree, bl_idname='ShaderNodeMath', name='metal_round')
colorize_rgb_picker = self.node(tree, bl_idname='ShaderNodeRGB', name='colorize_rgb_picker')
colorize_rgb_mix_node = self.node(tree, bl_idname='ShaderNodeMixRGB', name='colorize_rgb_mix_node')
object_info = self.node(tree, bl_idname='ShaderNodeObjectInfo', name='object_info')
if not clear:
# Mix Shader
if not final_mix_shader:
final_mix_shader = self.new_node(
tree,
bl_idname = 'ShaderNodeMixShader',
x = output.location.x-250,
y = output.location.y,
)
final_mix_shader.name = 'final_mix_shader'
final_mix_shader.label = 'final_mix_shader'
self.socket_connect(tree, final_mix_shader, output)
# Primary Hard Surface Shader
if not principled:
principled = self.new_node(tree,
bl_idname = 'ShaderNodeBsdfPrincipled',
x = output.location.x-1400,
y = output.location.y,
)
principled.name = 'principled'
principled.label = 'principled'
principled.location.x = output.location.x-1400
principled.location.y = output.location.y
self.socket_connect(tree, principled, final_mix_shader, 0, 0, socket_type='SHADER')
# CARPAINT BEGIN
if not principled_carpaint:
principled_carpaint = self.new_node(
tree,
bl_idname = 'ShaderNodeBsdfPrincipled',
x = principled.location.x,
y = principled.location.y-1400,
)
principled_carpaint.name = 'principled_carpaint'
principled_carpaint.label = 'principled_carpaint'
self.socket_connect(tree, principled_carpaint, final_mix_shader, 0, 1, socket_type='SHADER')
if bpy.app.version[0] < 4:
principled_carpaint.inputs['Clearcoat'].default_value = 1.0 # set clearcoat
principled_carpaint.inputs['Clearcoat'].default_value = 0.05 # set clearcoat roughness
else:
principled_carpaint.inputs['Coat Weight'].default_value = 1.0
principled_carpaint.inputs['Coat Roughness'].default_value = 0.05
if not carpaint_metallic_value:
carpaint_metallic_value = self.new_node(
tree,
bl_idname = 'ShaderNodeValue',
x = principled_carpaint.location.x-275,
y = principled_carpaint.location.y-300,
)
carpaint_metallic_value.name = 'carpaint_metallic_value'
carpaint_metallic_value.label = 'carpaint_metallic_value'
self.socket_connect(tree, carpaint_metallic_value, principled_carpaint, 0, 1, socket_type='VALUE')
if self.rampbased_carpaint_metallic:
carpaint_metallic_value.outputs[0].default_value = 1.0
else:
carpaint_metallic_value.outputs[0].default_value = 0.0
if not carpaint_hsv:
carpaint_hsv = self.new_node(
tree,
bl_idname = 'ShaderNodeHueSaturation',
x = principled_carpaint.location.x-275,
y = principled_carpaint.location.y,
)
carpaint_hsv.name = 'carpaint_hsv'
carpaint_hsv.label = 'carpaint_hsv'
self.socket_connect(tree, carpaint_hsv, principled_carpaint, 0, 0, socket_type='RGBA')
carpaint_hsv.inputs['Hue'].default_value = self.carpaint_hue_shift
carpaint_hsv.inputs['Saturation'].default_value = self.carpaint_saturation
carpaint_hsv.inputs['Value'].default_value = self.carpaint_value_brightness
if not carpaint_shift_mix:
carpaint_shift_mix = self.new_node(
tree,
bl_idname = 'ShaderNodeMixRGB',
x = carpaint_hsv.location.x-275,
y = carpaint_hsv.location.y-300,
)
carpaint_shift_mix.name = 'carpaint_shift_mix'
carpaint_shift_mix.label = 'carpaint_shift_mix'
self.socket_connect(tree, carpaint_shift_mix, carpaint_hsv, 0, 0, socket_type='RGBA', socket_to_type='VALUE')
carpaint_shift_mix.inputs['Fac'].default_value = self.carpaint_hue_variation / 100.0
if not carpaint_shift_value:
carpaint_shift_value = self.new_node(
tree,
bl_idname = 'ShaderNodeValue',
x = carpaint_shift_mix.location.x-275,
y = carpaint_shift_mix.location.y+100,
)
carpaint_shift_value.name = 'carpaint_shift_value'
carpaint_shift_value.label = 'carpaint_shift_value'
self.socket_connect(tree, carpaint_shift_value, carpaint_shift_mix, 0, 0, socket_type='VALUE', socket_to_type='RGBA')
carpaint_shift_value.outputs[0].default_value = self.carpaint_hue_shift
if not carpaint_shift_ramp:
carpaint_shift_ramp = self.new_node(
tree,
bl_idname = 'ShaderNodeValToRGB',
x = carpaint_shift_value.location.x-275,
y = carpaint_shift_value.location.y-100,
)
carpaint_shift_ramp.name = 'carpaint_shift_ramp'
carpaint_shift_ramp.label = 'carpaint_shift_ramp'
self.socket_connect(tree, carpaint_shift_ramp, carpaint_shift_mix, 0, 1, socket_type='RGBA')
if not carpaint_colorramp:
carpaint_colorramp = self.new_node(
tree,
bl_idname = 'ShaderNodeValToRGB',
x = carpaint_hsv.location.x-275,
y = carpaint_hsv.location.y,
)
carpaint_colorramp.name = 'carpaint_colorramp'
carpaint_colorramp.label = 'carpaint_colorramp'
self.socket_connect(tree, carpaint_colorramp, carpaint_hsv, 0, 0, socket_type='RGBA')
carpaint_colorramp.color_ramp.elements[0].color = self.carpaint_colorramp_start_color
carpaint_colorramp.color_ramp.elements[1].color = self.carpaint_colorramp_end_color
carpaint_colorramp.color_ramp.elements[1].position = 0.80
if not carpaint_layerweight:
carpaint_layerweight = self.new_node(
tree,
bl_idname = 'ShaderNodeLayerWeight',
x = carpaint_colorramp.location.x-275,
y = carpaint_colorramp.location.y,
)
carpaint_layerweight.name = 'carpaint_layerweight'
carpaint_layerweight.label = 'carpaint_layerweight'
self.socket_connect(tree, carpaint_layerweight, carpaint_colorramp, 1, 0, socket_type='VALUE')
if not carpaint_roughness_rgb_to_bw:
carpaint_roughness_rgb_to_bw = self.new_node(
tree,
bl_idname = 'ShaderNodeRGBToBW',
x = principled_carpaint.location.x-275,
y = principled_carpaint.location.y-600,
)
carpaint_roughness_rgb_to_bw.name = 'carpaint_roughness_rgb_to_bw'
carpaint_roughness_rgb_to_bw.label = 'carpaint_roughness_rgb_to_bw'
self.socket_connect(tree, carpaint_roughness_rgb_to_bw, principled_carpaint, 0, 4, socket_type='VALUE')
if not carpaint_roughness_ramp:
carpaint_roughness_ramp = self.new_node(
tree,
bl_idname = 'ShaderNodeValToRGB',
x = carpaint_roughness_rgb_to_bw.location.x-300,
y = carpaint_roughness_rgb_to_bw.location.y,
)
carpaint_roughness_ramp.name = 'carpaint_roughness_ramp'
carpaint_roughness_ramp.label = 'carpaint_roughness_ramp'
self.socket_connect(tree, carpaint_roughness_ramp, carpaint_roughness_rgb_to_bw, 0, 0, socket_type='RGBA')
carpaint_roughness_ramp.color_ramp.elements[0].color = self.carpaint_roughness_ramp_start
carpaint_roughness_ramp.color_ramp.elements[1].color = self.carpaint_roughness_ramp_end
if not carpaint_roughness_voronoi:
carpaint_roughness_voronoi = self.new_node(
tree,
bl_idname = 'ShaderNodeTexVoronoi',
x = carpaint_roughness_ramp.location.x-300,
y = carpaint_roughness_ramp.location.y,
)
carpaint_roughness_voronoi.name = 'carpaint_roughness_voronoi'
carpaint_roughness_voronoi.label = 'carpaint_roughness_voronoi'
self.socket_connect(
tree,
carpaint_roughness_voronoi,
carpaint_roughness_ramp,
0,
0,
socket_type='RGBA',
socket_to_type='VALUE'
)
carpaint_roughness_voronoi.voronoi_dimensions = '4D'
carpaint_roughness_voronoi.feature = 'F1'
carpaint_roughness_voronoi.distance = 'EUCLIDEAN'
carpaint_roughness_voronoi.inputs['Scale'].default_value = self.carpaint_roughness_scale
if not tex_coord:
tex_coord = self.new_node(
tree,
bl_idname = 'ShaderNodeTexCoord',
x = carpaint_roughness_voronoi.location.x-300,
y = carpaint_roughness_voronoi.location.y,
)
tex_coord.name = 'tex_coord'
tex_coord.label = 'tex_coord'
self.socket_connect(tree, tex_coord, carpaint_roughness_voronoi, 3, 0, socket_type='VECTOR')
# CARPAINT END
# COLORIZATION START
if not colorize_rgb_mix_node:
colorize_rgb_mix_node = self.new_node(tree,
bl_idname = 'ShaderNodeMixRGB',
x = principled.location.x-200,
y = principled.location.y,
)
colorize_rgb_mix_node.name = 'colorize_rgb_mix_node'
colorize_rgb_mix_node.label = 'colorize_rgb_mix_node'
colorize_rgb_mix_node.location.x = principled.location.x-200
colorize_rgb_mix_node.location.y = principled.location.y+400
self.socket_connect(tree, colorize_rgb_mix_node, principled, socket_type='RGBA')
if not colorize_rgb_picker:
colorize_rgb_picker = self.new_node(
tree,
bl_idname = 'ShaderNodeRGB',
x = colorize_rgb_mix_node.location.x-275,
y = colorize_rgb_mix_node.location.y-125,
)
colorize_rgb_picker.outputs[0].default_value = self.colorize_rgb
colorize_rgb_picker.name = 'colorize_rgb_picker'
colorize_rgb_picker.label = 'colorize_rgb_picker'
colorize_rgb_picker.location.x = colorize_rgb_mix_node.location.x-275
colorize_rgb_picker.location.y = colorize_rgb_mix_node.location.y-125
self.socket_connect(tree, colorize_rgb_picker, colorize_rgb_mix_node, 0, 1, socket_type='RGBA')
if not basecolor_ramp:
basecolor_ramp = self.new_node(
tree,
bl_idname = 'ShaderNodeValToRGB',
x = colorize_rgb_mix_node.location.x-275,
y = colorize_rgb_mix_node.location.y+125,
)
basecolor_ramp.name = 'basecolor_ramp'
basecolor_ramp.label = 'basecolor_ramp'
basecolor_ramp.color_ramp.elements[0].color = self.rampbased_ramp_start
basecolor_ramp.color_ramp.elements[1].color = self.rampbased_ramp_end
basecolor_ramp.color_ramp.elements[1].position = self.rampbased_ramp_spread
self.socket_connect(tree, basecolor_ramp, colorize_rgb_mix_node, socket_type='RGBA')
if not object_info:
object_info = self.new_node(
tree,
bl_idname = 'ShaderNodeObjectInfo',
x = basecolor_ramp.location.x-250,
y = basecolor_ramp.location.y,
)
object_info.name = 'object_info'
object_info.label = 'object_info'
self.socket_connect(tree, object_info, basecolor_ramp, 2, 0, socket_type='VALUE') # from 'Random' to 'Fac'
self.socket_connect(tree, object_info, carpaint_shift_ramp, 2, 0, socket_type='VALUE')
# COLORIZATION END
# ROUGHNESS START
if not roughness_rgb_to_bw:
roughness_rgb_to_bw = self.new_node(
tree,
bl_idname = 'ShaderNodeRGBToBW',
x = principled.location.x-200,
y = principled.location.y,
)
roughness_rgb_to_bw.name = 'roughness_rgb_to_bw'
roughness_rgb_to_bw.label = 'roughness_rgb_to_bw'
self.socket_connect(tree, roughness_rgb_to_bw, principled, 0, 4, socket_type='VALUE')
if not roughness_ramp:
roughness_ramp = self.new_node(
tree,
bl_idname='ShaderNodeValToRGB',
x = roughness_rgb_to_bw.location.x-275,
y = roughness_rgb_to_bw.location.y,
)
roughness_ramp.name = 'roughness_ramp'
roughness_ramp.label = 'roughness_ramp'
self.socket_connect(tree, roughness_ramp, roughness_rgb_to_bw, 0, 0, socket_type='RGBA')
self.socket_connect(tree, object_info, roughness_ramp, 2, 0, socket_type='VALUE')
roughness_ramp_start = [0.0, 0.0, 0.0, 1.0]
roughness_ramp_end = [0.0, 0.0, 0.0, 1.0]
for index, value in enumerate(roughness_ramp_start[:3]):
roughness_ramp_start[index] = self.rampbased_roughness_min
for index, value in enumerate(roughness_ramp_end[:3]):
roughness_ramp_end[index] = self.rampbased_roughness_max
roughness_ramp.color_ramp.elements[0].color = roughness_ramp_start
roughness_ramp.color_ramp.elements[1].color = roughness_ramp_end
# ROUGHNESS END
# CARPAINT PROBABILITY START
if not carpaint_round:
carpaint_round = self.new_node(
tree,
bl_idname='ShaderNodeMath',
x = final_mix_shader.location.x-200,
y = final_mix_shader.location.y+500,
)
carpaint_round.name = 'carpaint_round'
carpaint_round.label = 'carpaint_round'
carpaint_round.operation = 'ROUND'
carpaint_round.use_clamp = True
self.socket_connect(tree, carpaint_round, final_mix_shader, 0, 0, socket_type='VALUE')
if not carpaint_rgb_to_bw:
carpaint_rgb_to_bw = self.new_node(
tree,
bl_idname='ShaderNodeRGBToBW',
x = carpaint_round.location.x-200,
y = carpaint_round.location.y,
)
carpaint_rgb_to_bw.name = 'carpaint_rgb_to_bw'
carpaint_rgb_to_bw.label = 'carpaint_rgb_to_bw'
self.socket_connect(tree, carpaint_rgb_to_bw, carpaint_round, 0, 0, socket_type='VALUE')
if not carpaint_ramp:
carpaint_ramp = self.new_node(
tree,
bl_idname = 'ShaderNodeValToRGB',
x = carpaint_rgb_to_bw.location.x-275,
y = carpaint_rgb_to_bw.location.y,
)
carpaint_ramp.name = 'carpaint_ramp'
carpaint_ramp.label = 'carpaint_ramp'
self.socket_connect(tree, carpaint_ramp, carpaint_rgb_to_bw, 0, 0, socket_type='RGBA')
self.socket_connect(tree, object_info, carpaint_ramp, 2, 0, socket_type='VALUE')
carpaint_ramp.color_ramp.interpolation = 'CONSTANT'
if self.rampbased_carpaint_probability == 100.0 or self.rampbased_carpaint_probability == 0.0:
if len(carpaint_ramp.color_ramp.elements.values()) > 1:
for element in carpaint_ramp.color_ramp.elements.values()[1:]:
carpaint_ramp.color_ramp.elements.remove(element)
tmp_v = self.rampbased_carpaint_probability / 100.0
carpaint_ramp.color_ramp.elements[0].color = [tmp_v, tmp_v, tmp_v, 1.0]
carpaint_ramp.color_ramp.elements[0].position = 0.0
else:
if len(carpaint_ramp.color_ramp.elements.values()) != 2:
for element in carpaint_ramp.color_ramp.elements.values()[1:]:
carpaint_ramp.color_ramp.elements.remove(element)
carpaint_ramp.color_ramp.elements.new(1.0)
carpaint_ramp.color_ramp.elements[0].position = 0.0
carpaint_ramp.color_ramp.elements[0].color = [0.0, 0.0, 0.0, 1.0]
carpaint_ramp.color_ramp.elements[1].position = 1.0 - (self.rampbased_carpaint_probability / 100.0)
carpaint_ramp.color_ramp.elements[1].color = [1.0, 1.0, 1.0, 1.0]
# CARPAINT PROBABILITY END
# METAL START
if not metal_round:
metal_round = self.new_node(
tree,
bl_idname='ShaderNodeMath',
x = principled.location.x-200,
y = principled.location.y-300,
)
metal_round.name = 'metal_round'
metal_round.label = 'metal_round'
metal_round.operation = 'ROUND'
metal_round.use_clamp = True
self.socket_connect(tree, metal_round, principled, 0, 1, socket_type='VALUE')
if not metal_rgb_to_bw:
metal_rgb_to_bw = self.new_node(
tree,
bl_idname='ShaderNodeRGBToBW',
x = metal_round.location.x-200,
y = metal_round.location.y,
)
metal_rgb_to_bw.name = 'metal_rgb_to_bw'
metal_rgb_to_bw.label = 'metal_rgb_to_bw'
self.socket_connect(tree, metal_rgb_to_bw, metal_round, 0, 0, socket_type='VALUE')
if not metal_ramp:
metal_ramp = self.new_node(
tree,
bl_idname='ShaderNodeValToRGB',
x = metal_rgb_to_bw.location.x-275,
y = metal_rgb_to_bw.location.y,
)
metal_ramp.name = 'metal_ramp'
metal_ramp.label = 'metal_ramp'
self.socket_connect(tree, metal_ramp, metal_rgb_to_bw, 0, 0, socket_type='RGBA')
self.socket_connect(tree, object_info, metal_ramp, 2, 0, socket_type='VALUE')
metal_ramp.color_ramp.interpolation = 'CONSTANT'
if self.rampbased_metal_probability == 100.0 or self.rampbased_metal_probability == 0.0:
if len(metal_ramp.color_ramp.elements.values()) > 1:
for element in metal_ramp.color_ramp.elements.values()[1:]:
metal_ramp.color_ramp.elements.remove(element)
tmp_v = self.rampbased_metal_probability / 100.0
metal_ramp.color_ramp.elements[0].color = [tmp_v, tmp_v, tmp_v, 1.0]
metal_ramp.color_ramp.elements[0].position = 0.0
else:
if len(metal_ramp.color_ramp.elements.values()) != 2:
for element in metal_ramp.color_ramp.elements.values()[1:]:
metal_ramp.color_ramp.elements.remove(element)
metal_ramp.color_ramp.elements.new(1.0)
metal_ramp.color_ramp.elements[0].position = 0.0
metal_ramp.color_ramp.elements[0].color = [0.0, 0.0, 0.0, 1.0]
metal_ramp.color_ramp.elements[1].position = 1.0 - (self.rampbased_metal_probability / 100.0)
metal_ramp.color_ramp.elements[1].color = [1.0, 1.0, 1.0, 1.0]
# METAL END
# CLEARCOAT START
if not clearcoat_round:
clearcoat_round = self.new_node(
tree,
bl_idname='ShaderNodeMath',
x = principled.location.x-200,
y = principled.location.y-600,
)
clearcoat_round.name = 'clearcoat_round'
clearcoat_round.label = 'clearcoat_round'
clearcoat_round.operation = 'ROUND'
clearcoat_round.use_clamp = True
self.socket_connect(tree, clearcoat_round, principled, 0, 9, socket_type='VALUE')
if not clearcoat_rgb_to_bw:
clearcoat_rgb_to_bw = self.new_node(
tree,
bl_idname='ShaderNodeRGBToBW',
x = clearcoat_round.location.x-200,
y = clearcoat_round.location.y,
)
clearcoat_rgb_to_bw.name = 'clearcoat_rgb_to_bw'
clearcoat_rgb_to_bw.label = 'clearcoat_rgb_to_bw'
self.socket_connect(tree, clearcoat_rgb_to_bw, clearcoat_round, 0, 0, socket_type='VALUE')
if not clearcoat_ramp:
clearcoat_ramp = self.new_node(
tree,
bl_idname='ShaderNodeValToRGB',
x = clearcoat_rgb_to_bw.location.x-275,
y = clearcoat_rgb_to_bw.location.y,
)
clearcoat_ramp.name = 'clearcoat_ramp'
clearcoat_ramp.label = 'clearcoat_ramp'
self.socket_connect(tree, clearcoat_ramp, clearcoat_rgb_to_bw, 0, 0, socket_type='RGBA')
self.socket_connect(tree, object_info, clearcoat_ramp, 2, 0, socket_type='VALUE')
clearcoat_ramp.color_ramp.interpolation = 'CONSTANT'
if self.rampbased_clearcoat_probability == 100.0 or self.rampbased_clearcoat_probability == 0.0:
if len(clearcoat_ramp.color_ramp.elements.values()) > 1:
for element in clearcoat_ramp.color_ramp.elements.values()[1:]:
clearcoat_ramp.color_ramp.elements.remove(element)
tmp_v = self.rampbased_clearcoat_probability / 100.0
clearcoat_ramp.color_ramp.elements[0].color = [tmp_v, tmp_v, tmp_v, 1.0]
clearcoat_ramp.color_ramp.elements[0].position = 0.0
else:
if len(clearcoat_ramp.color_ramp.elements.values()) != 2:
for element in clearcoat_ramp.color_ramp.elements.values()[1:]:
clearcoat_ramp.color_ramp.elements.remove(element)
clearcoat_ramp.color_ramp.elements.new(1.0)
clearcoat_ramp.color_ramp.elements[0].position = 0.0
clearcoat_ramp.color_ramp.elements[0].color = [0.0, 0.0, 0.0, 1.0]
clearcoat_ramp.color_ramp.elements[1].position = 1.0 - (self.rampbased_clearcoat_probability / 100.0)
clearcoat_ramp.color_ramp.elements[1].color = [1.0, 1.0, 1.0, 1.0]
# CLEARCOAT END
colorize_rgb_mix_node.mute = not self.colorize
return
if principled:
tree.nodes.remove(principled)
if principled_carpaint:
tree.nodes.remove(principled_carpaint)
def emission(self, mat, clear=True):
tree = mat.node_tree
output = self.node(tree, bl_idname='ShaderNodeOutputMaterial')
emission = self.node(tree, bl_idname='ShaderNodeEmission')
if not clear:
if not emission:
emission = self.new_node(tree,
bl_idname = 'ShaderNodeEmission',
x = output.location.x-180,
y = output.location.y)
self.socket(emission, type='inputs', socket_type='RGBA').default_value = self.random
self.socket_connect(tree, emission, output)
multiply = self.new_node(tree,
bl_idname = 'ShaderNodeMath',
x = emission.location.x-180,
y = emission.location.y)
self.socket(multiply, type='inputs', socket_type='VALUE', index=1).default_value = 8
multiply.operation = 'MULTIPLY'
self.socket_connect(tree, multiply, emission, socket_type='VALUE')
floor = self.new_node(tree,
bl_idname = 'ShaderNodeMath',
x = multiply.location.x-180,
y = multiply.location.y)
floor.use_clamp = True
floor.operation = 'FLOOR'
self.socket_connect(tree, floor, multiply, socket_type='VALUE')
arctan2 = self.new_node(tree,
bl_idname = 'ShaderNodeMath',
x = floor.location.x-180,
y = floor.location.y)
arctan2.operation = 'ARCTAN2'
if self.pulse:
driven_path = self.socket(
arctan2,
type = 'inputs',
socket_type = 'VALUE',
path_id = 'default_value')
new = tree.driver_add(driven_path)
new.driver.type = 'SCRIPTED'
new.driver.expression = f'cos(frame*pi/{30/self.frequency})'
self.socket_connect(tree, arctan2, floor, socket_type='VALUE')
self.socket(arctan2, type='inputs', socket_type='VALUE', index=1).default_value = 0.2
return
connected = self.connected_nodes(emission, [])
for node in connected:
tree.nodes.remove(node)
# tree.nodes.remove(emission)
# 50% alpha in workbench view
def glass(self, mat, clear=True):
tree = mat.node_tree
output = self.node(tree, bl_idname='ShaderNodeOutputMaterial')
mix = self.node(mat.node_tree, bl_idname='ShaderNodeMixShader')
if not clear:
if not mix:
mix = self.new_node(tree,
bl_idname = 'ShaderNodeMixShader',
x = output.location.x-180,
y = output.location.y)
self.socket_connect(tree, mix, output)
color_ramp = self.new_node(tree,
bl_idname = 'ShaderNodeValToRGB',
x = mix.location.x-280,
y = mix.location.y+150)
color_ramp.color_ramp.elements[1].position = 0.3
color_ramp.color_ramp.elements[1].color = (0.6, 0.6, 0.6, 1.0)
self.socket_connect(tree, color_ramp, mix, socket_type='RGBA', socket_to_type='VALUE')
fresnel = self.new_node(tree,
bl_idname = 'ShaderNodeFresnel',
x = color_ramp.location.x-180,
y = color_ramp.location.y-100)
self.socket_connect(tree, fresnel, color_ramp, socket_type='VALUE')
glass = self.new_node(tree,
bl_idname = 'ShaderNodeBsdfGlass',
x = fresnel.location.x,
y = fresnel.location.y-220)
self.socket(glass, type='inputs', socket_type='VALUE').default_value = 0.1
self.socket_connect(tree, glass, mix, index_to=1)
transparent = self.new_node(tree,
bl_idname = 'ShaderNodeBsdfTransparent',
x = fresnel.location.x,
y = fresnel.location.y-120)
self.socket(transparent, type='inputs', socket_type='RGBA').default_value = (0.6, 0.6, 0.6, 1.0)
self.socket_connect(tree, transparent, mix)
value = self.new_node(tree,
bl_idname = 'ShaderNodeValue',
x = transparent.location.x-180,
y = transparent.location.y)
self.socket(value, socket_type='VALUE').default_value = 1.45
self.socket_connect(tree, value, fresnel, socket_type='VALUE')
self.socket_connect(tree, value, glass, socket_type='VALUE', index_to=1)
return
connected = self.connected_nodes(mix, [])
for node in connected:
tree.nodes.remove(node)
# tree.nodes.remove(mix)
def uv(self, mat, clear=None):
tree = mat.node_tree
tree.nodes.clear()
x_offset = 0
out = tree.nodes.new("ShaderNodeOutputMaterial")
x_offset -=300
principled = tree.nodes.new("ShaderNodeBsdfPrincipled")
principled.location.x = x_offset
tree.links.new(principled.outputs[0], out.inputs[0])
x_offset -= 300
tex = tree.nodes.new("ShaderNodeTexImage")
tex.location.x = x_offset
tree.links.new(principled.inputs[0], tex.outputs[0])
images = [i for i in bpy.data.images if i.source =='GENERATED' and i.generated_type == self.uv_texture]
# reused existing image
if images:
tex.image = images[0]
else:
img = bpy.data.images.new('Color Grid', 1024, 1024)
img.source = 'GENERATED'
img.generated_type = self.uv_texture
tex.image = img
x_offset -= 200
mapping = tree.nodes.new("ShaderNodeMapping")
mapping.location.x = x_offset
tree.links.new(mapping.outputs[0], tex.inputs[0])
x_offset -= 200
text_space = tree.nodes.new("ShaderNodeTexCoord")
tree.links.new(text_space.outputs[2], mapping.inputs[0])
text_space.location.x = x_offset
def invoke(self, context, event):
self.copy_view = addon.preference().behavior.mat_viewport
if event.ctrl and not event.shift:
self.unique = True
self.type = 'PRINCIPLED'
if addon.preference().ui.Hops_extra_info:
bpy.ops.hops.display_notification(info=F'Blank Material - Principle (unique)')
elif event.shift and not event.ctrl:
self.type = 'GLASS'
if addon.preference().ui.Hops_extra_info:
bpy.ops.hops.display_notification(info=F'Blank Material - Glass')
elif event.alt and not event.shift and not event.ctrl:
self.type = 'EMISSION'
if addon.preference().ui.Hops_extra_info:
bpy.ops.hops.display_notification(info=F'Blank Material - Emission')
elif event.shift and event.ctrl and not event.alt:
self.type = 'UV'
if addon.preference().ui.Hops_extra_info:
bpy.ops.hops.display_notification(info=F'Blank Material - UV')
elif self.helper_call:
self.type = 'PRINCIPLED'
# if addon.preference().ui.Hops_extra_info:
# bpy.ops.hops.display_notification(info=F'Blank Material - Principle' )
else:
self.type = 'PRINCIPLED'
if addon.preference().ui.Hops_extra_info:
bpy.ops.hops.display_notification(info=F'Blank Material - Principle')
return self.execute(context)
def execute(self, context):
blend_method = 'OPAQUE' if self.type != 'GLASS' else 'BLEND'
name = self.type.title() if self.type != 'PRINCIPLED' else 'Material'
mat = self.new(name=name, blend_method=blend_method)
if self.type == 'GLASS':
mat.diffuse_color = (0.5, 0.5, 0.5, 0.5)
mat.metallic = 1
mat.roughness = 0
if self.type != 'PRINCIPLED':
self.principled(mat)
self.random = random_color()
getattr(self, self.type.lower())(mat, clear=False)
if self.type == 'EMISSION':
mat.diffuse_color = self.random if not self.copy_view else mat.diffuse_color
mat.roughness = 0
if self.helper_call:
self.helper_call = False
context.active_object.active_material = mat
if self.type == 'PRINCIPLED':
mat.diffuse_color = self.random if not self.copy_view else mat.diffuse_color
return {'FINISHED'}
selected = context.selected_objects[:]
in_mode = context.objects_in_mode[:]
objects = set(selected + in_mode)
for obj in objects:
if obj.type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT'}:
if self.unique and self.type != 'GLASS' and self.type != 'RAMPBASED' and self.type != 'CARPAINT':
mat = self.new(blend_method=blend_method)
if self.type != 'PRINCIPLED':
self.principled(mat)
self.random = random_color()
getattr(self, self.type.lower())(mat, clear=False)
if self.type == 'EMISSION':
mat.diffuse_color = self.random if not self.copy_view else mat.diffuse_color
mat.roughness = 0
#add(context, obj, mat=mat, append=False, viewport=self.type == 'PRINCIPLED')
if self.active_only:
obj.active_material = mat
else:
add(context, obj, mat=mat, append=False, viewport=not self.copy_view)
#Add is undoing glass atm (will need fixing)
if self.type == 'GLASS':
mat.diffuse_color[3] = 0.5
if self.cleanup:
mat_by_name = [mat.name for mat in bpy.data.materials]
for name in mat_by_name:
if not bpy.data.materials[name].users:
bpy.data.materials.remove(bpy.data.materials[name])
return {'FINISHED'}
def draw(self, context):
layout = self.layout
column = layout.column()
row = column.row()
row.prop(self, 'type', expand=True)
if self.type == 'PRINCIPLED':
self.label_row(column.row(), 'Unique Material', 'unique')
self.label_row(column.row(), 'Colorize', 'colorize')
self.label_row(column.row(), 'Colorize RGB', 'colorize_rgb')
self.label_row(column.row(), 'Clearcoat', 'clearcoat')
if not self.colorize:
column.separator()
self.label_row(column.row(), 'Grayscale', 'grayscale')
column.separator()
self.label_row(column.row(), 'Clamp', 'clamp')
self.label_row(column.row(), 'Advanced Clamp Options', 'clamp_expand')
if self.clamp_expand:
self.label_row(column.row(), 'Clamp Min', 'clamp_min_nonmetals')
self.label_row(column.row(), 'Clamp Max', 'clamp_max_nonmetals')
self.label_row(column.row(), 'Clamp Min', 'clamp_min_metals')
self.label_row(column.row(), 'Clamp Max', 'clamp_max_metals')
self.label_row(column.row(), 'Bevel Shader','bevel_shader')
if self.bevel_shader:
self.label_row(column.row(), 'Samples','bevel_shader_samples')
self.label_row(column.row(), 'Radius','bevel_shader_radius')
if self.type == 'GLASS':
pass # currently no extra options needed, placeholder
if self.type == 'EMISSION':
self.label_row(column.row(), 'Unique Material', 'unique')
self.label_row(column.row(), 'Pulse', 'pulse')
self.label_row(column.row(), 'Frequency', 'frequency')
if self.type == 'CARPAINT':
self.label_row(column.row(), 'Carpaint Metallic', 'rampbased_carpaint_metallic')
self.label_row(column.row(), 'Carpaint Hue Shift', 'carpaint_hue_shift')
self.label_row(column.row(), 'Carpaint Hue Variation', 'carpaint_hue_variation')
self.label_row(column.row(), 'Carpaint Saturation', 'carpaint_saturation')
self.label_row(column.row(), 'Carpaint Brightness', 'carpaint_value_brightness')
self.label_row(column.row(), 'Advanced Carpaint Options', 'carpaint_expand_advanced')
if self.carpaint_expand_advanced:
self.label_row(column.row(), 'Carpaint Roughness Ramp Start', 'carpaint_roughness_ramp_start')
self.label_row(column.row(), 'Carpaint Roughness Ramp End', 'carpaint_roughness_ramp_end')
self.label_row(column.row(), 'Carpaint Roughness Scale', 'carpaint_roughness_scale')
self.label_row(column.row(), 'Carpaint Color Start', 'carpaint_colorramp_start_color')
self.label_row(column.row(), 'Carpaint Color End', 'carpaint_colorramp_end_color')
if self.type == 'GENERAL':
self.label_row(column.row(), 'Colorize', 'colorize')
self.label_row(column.row(), 'Colorize RGB', 'colorize_rgb')
column.separator()
self.label_row(column.row(), 'Advanced Carpaint Options', 'carpaint_expand_advanced')
if self.carpaint_expand_advanced:
self.label_row(column.row(), 'Carpaint Metallic', 'rampbased_carpaint_metallic')
self.label_row(column.row(), 'Carpaint Probability', 'rampbased_carpaint_probability')
self.label_row(column.row(), 'Carpaint Hue Shift', 'carpaint_hue_shift')
self.label_row(column.row(), 'Carpaint Hue Variation', 'carpaint_hue_variation')
self.label_row(column.row(), 'Carpaint Saturation', 'carpaint_saturation')
self.label_row(column.row(), 'Carpaint Brightness', 'carpaint_value_brightness')
self.label_row(column.row(), 'Carpaint Roughness Ramp Start', 'carpaint_roughness_ramp_start')
self.label_row(column.row(), 'Carpaint Roughness Ramp End', 'carpaint_roughness_ramp_end')
self.label_row(column.row(), 'Carpaint Roughness Scale', 'carpaint_roughness_scale')
self.label_row(column.row(), 'Carpaint Color Start', 'carpaint_colorramp_start_color')
self.label_row(column.row(), 'Carpaint Color End', 'carpaint_colorramp_end_color')
column.separator()
self.label_row(column.row(), 'Metal Probability', 'rampbased_metal_probability')
self.label_row(column.row(), 'Clearcoat Probability', 'rampbased_clearcoat_probability')
column.separator()
self.label_row(column.row(), 'Roughness Min', 'rampbased_roughness_min')
self.label_row(column.row(), 'Roughness Max', 'rampbased_roughness_max')
column.separator()
self.label_row(column.row(), 'Ramp Start', 'rampbased_ramp_start')
self.label_row(column.row(), 'Ramp End', 'rampbased_ramp_end')
self.label_row(column.row(), 'Ramp Spread', 'rampbased_ramp_spread')
column.separator()
self.label_row(column.row(), 'Remove Zero User Materials', 'cleanup')
column.separator()
self.label_row(column.row(), 'Active Only', 'active_only')
if self.type == 'UV':
self.label_row(column.row(), 'Texture', 'uv_texture')
def label_row(self, row, label, prop):
row.label(text=label)
row.prop(self, prop, text='')