Skip to content

Instantly share code, notes, and snippets.

@CGArtPython
Created September 28, 2021 05:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CGArtPython/e59fa975cec458c3adb2669fe58e09e9 to your computer and use it in GitHub Desktop.
Save CGArtPython/e59fa975cec458c3adb2669fe58e09e9 to your computer and use it in GitHub Desktop.
"""
Author: Viktor Stepanov
Licence: MIT
The code for this art:
https://www.artstation.com/artwork/L3oVvv
Tested with Blender 2.93
"""
import math
import random
import time
import bpy
import mathutils
def delete_all_objects():
"""
Removing all of the objects from the scene
"""
if bpy.context.active_object and bpy.context.active_object.mode == "EDIT":
bpy.ops.object.editmode_toggle()
for obj in bpy.data.objects:
obj.hide_set(False)
obj.hide_select = False
obj.hide_viewport = False
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete()
cl = [c.name for c in bpy.data.collections]
for name in cl:
bpy.data.collections.remove(bpy.data.collections[name])
acs = [ac.name for ac in bpy.data.actions]
for name in acs:
bpy.data.actions.remove(bpy.data.actions[name])
cms = [cm.name for cm in bpy.data.cameras]
for name in cms:
bpy.data.cameras.remove(bpy.data.cameras[name])
cms = [cm.name for cm in bpy.data.curves]
for name in cms:
bpy.data.curves.remove(bpy.data.curves[name])
# free the rest of the data materials, particles, textures, meshes, geo nodes
bpy.ops.outliner.orphans_purge(
do_local_ids=True,
do_linked_ids=True,
do_recursive=True,
)
def get_color_palette():
# https://www.colourlovers.com/palette/92095/Giant_Goldfish
# palette = ["#69D2E7FF", "#E0E4CCFF", "#F38630FF", "#A7DBD8FF", "#FA6900FF"]
palette = [
[0.41015625, 0.8203125, 0.90234375, 0.99609375],
[0.875, 0.890625, 0.796875, 0.99609375],
[0.94921875, 0.5234375, 0.1875, 0.99609375],
[0.65234375, 0.85546875, 0.84375, 0.99609375],
[0.9765625, 0.41015625, 0.0, 0.99609375],
]
return palette
def get_random_pallet_color(context):
return random.choice(context["colors"])
def active_obj():
"""
returns the active object
"""
return bpy.context.active_object
def time_seed():
"""
Sets the random seed based on the time
and copies the seed into the clipboard
"""
seed = time.time()
print(f"seed: {seed}")
random.seed(seed)
bpy.context.window_manager.clipboard = str(seed)
return seed
def shade_smooth():
bpy.ops.object.shade_smooth()
bpy.context.object.data.use_auto_smooth = True
def add_ico_sphere(
subdivisions=3,
radius=1,
location=(0, 0, 0),
scale=(1, 1, 1),
rotation=(0, 0, 0),
scale_factor=None,
apply_shade_smooth=True,
):
"""
Creates an ico sphere
"""
bpy.ops.mesh.primitive_ico_sphere_add(
subdivisions=subdivisions,
radius=radius,
enter_editmode=False,
align="WORLD",
location=location,
)
obj = active_obj()
if scale_factor:
obj.scale *= scale_factor
else:
obj.scale = scale
obj.rotation_euler = rotation
if apply_shade_smooth:
shade_smooth()
return obj
def add_ctrl_empty(name=None):
bpy.ops.object.empty_add(
type="PLAIN_AXES", align="WORLD", location=(0, 0, 0), scale=(1, 1, 1)
)
empty_ctrl = bpy.context.active_object
if name:
empty_ctrl.name = name
else:
empty_ctrl.name = "empty.cntrl"
return empty_ctrl
def apply_mat(material):
obj = bpy.context.active_object
obj.data.materials.append(material)
def make_active(obj):
bpy.ops.object.select_all(action="DESELECT")
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
def make_node_tree_fcurves_linear(node_tree):
for fc in node_tree.animation_data.action.fcurves:
fc.extrapolation = "LINEAR"
def track_empty(cam):
bpy.ops.object.empty_add(type="PLAIN_AXES", align="WORLD", location=(0, 0, 0))
empty = active_obj()
empty.name = "tracker-target"
make_active(cam)
bpy.ops.object.constraint_add(type="TRACK_TO")
bpy.context.object.constraints["Track To"].target = empty
return empty
def setup_camera():
loc = (3.611, -3.895, 2.747)
rot = (1.076, 0.012, 0.746)
bpy.ops.object.camera_add(
enter_editmode=False, align="VIEW", location=loc, rotation=rot
)
cam = bpy.context.active_object
bpy.context.scene.camera = cam
bpy.context.object.data.lens = 70
bpy.context.object.data.passepartout_alpha = 0.9
empty = track_empty(cam)
empty.location.z = 0
def set_scene_props(context, fps, loop_sec):
"""
Set scene properties
"""
frame_count = fps * loop_sec
scene = bpy.context.scene
scene.frame_end = frame_count
world = bpy.data.worlds["World"]
if "Background" in world.node_tree.nodes:
world.node_tree.nodes["Background"].inputs[0].default_value = (0.0, 0.0, 0.0, 1)
bpy.context.scene.render.fps = fps
bpy.context.scene.eevee.use_bloom = True
bpy.context.scene.eevee.bloom_intensity = 0.005
bpy.context.scene.eevee.use_gtao = True
bpy.context.scene.eevee.use_ssr = True
bpy.context.scene.eevee.use_ssr_halfres = False
bpy.context.scene.eevee.ssr_quality = 1
bpy.context.scene.render.resolution_x = 1080
bpy.context.scene.render.resolution_y = 1080
def gen_light_rig_part(light_type):
bpy.ops.object.empty_add(
type="PLAIN_AXES", align="WORLD", location=(0, 0, 0), scale=(1, 1, 1)
)
emp_tracker = active_obj()
bpy.ops.curve.primitive_bezier_circle_add(
enter_editmode=False, align="WORLD", location=(0, 0, 0), scale=(1, 1, 1)
)
rail_curve = active_obj()
bpy.ops.object.light_add(
type=light_type, radius=1, align="WORLD", location=(0, 0, 0), scale=(1, 1, 1)
)
light = active_obj()
bpy.ops.object.constraint_add(type="TRACK_TO")
bpy.context.object.constraints["Track To"].target = emp_tracker
bpy.context.object.constraints["Track To"].track_axis = "TRACK_NEGATIVE_Z"
bpy.context.object.constraints["Track To"].up_axis = "UP_Y"
bpy.ops.object.constraint_add(type="FOLLOW_PATH")
follow_path = bpy.context.object.constraints["Follow Path"]
bpy.context.object.constraints["Follow Path"].target = rail_curve
bpy.context.object.constraints["Follow Path"].forward_axis = "TRACK_NEGATIVE_X"
bpy.context.object.constraints["Follow Path"].up_axis = "UP_Y"
bpy.context.object.constraints["Follow Path"].use_fixed_location = True
bpy.context.object.constraints["Follow Path"].use_curve_follow = True
return rail_curve, emp_tracker, light, follow_path
def add_lights_rig(context):
"""
Setup the lights for the scene
"""
ctrl_empty = add_ctrl_empty()
ctrl_empty.name = "_sun_ctrl"
rail_curve, _, light, follow_path = gen_light_rig_part("SUN")
light.data.color = get_random_pallet_color(context)[:3]
rail_curve.scale *= 2
light.data.angle = math.pi
light.data.energy = 0.1
rail_curve.parent = ctrl_empty
follow_path.offset_factor = 0.5
rail_curve, _, light, follow_path = gen_light_rig_part("SUN")
light.data.color = (1, 1, 1)
rail_curve.parent = ctrl_empty
rail_curve.scale *= 2
light.data.angle = math.pi
light.data.energy = 5
def gen_sphere_brush(context):
brush_instance = add_ico_sphere(subdivisions=5)
brush_instance.name = "brush_instance"
brush_instance.location.z = 10
brush = add_ico_sphere(subdivisions=5)
brush.name = "brush_geo"
apply_mat(context["martial_metal"])
context["point_instance_1_object"] = brush_instance
gen_geo_nodes_brush(context)
bpy.ops.object.modifier_add(type="DYNAMIC_PAINT")
dpaint = bpy.context.object.modifiers["Dynamic Paint"]
dpaint.ui_type = "BRUSH"
bpy.ops.dpaint.type_toggle(type="BRUSH")
dpaint.brush_settings.paint_wetness = 0.5
dpaint.brush_settings.paint_source = "VOLUME_DISTANCE"
dpaint.brush_settings.paint_distance = 0.1
def gen_point_distribute_0(context, node_tree):
point_distribute_0 = node_tree.nodes.new(type="GeometryNodePointDistribute")
# Attributes
point_distribute_0.distribute_method = "POISSON"
# point_distribute_0.label = ""
point_distribute_0.name = "Point Distribute"
point_distribute_0.location = mathutils.Vector((-568.904, 31.164))
# Input Socket
point_distribute_0.inputs["Distance Min"].default_value = 0.7 # 1.169
point_distribute_0.inputs["Density Max"].default_value = 9.899
point_distribute_0.inputs["Seed"].default_value = 0
return point_distribute_0
def gen_point_instance_1(context, node_tree):
point_instance_1 = node_tree.nodes.new(type="GeometryNodePointInstance")
# Attributes
point_instance_1.instance_type = "OBJECT"
point_instance_1.use_whole_collection = True
point_instance_1.name = "Point Instance"
# point_instance_1.label = ""
point_instance_1.location = mathutils.Vector((91.095, -3.591))
# Input Socket
point_instance_1.inputs["Object"].default_value = context["point_instance_1_object"]
# point_instance_1.inputs["Collection"].default_value = None
point_instance_1.inputs["Seed"].default_value = 0
return point_instance_1
def gen_point_scale_2(context, node_tree):
point_scale_2 = node_tree.nodes.new(type="GeometryNodePointScale")
# Attributes
point_scale_2.input_type = "VECTOR"
# point_scale_2.label = ""
point_scale_2.name = "Point Scale"
point_scale_2.location = mathutils.Vector((-348.904, 19.615))
# Input Socket
# point_scale_2.inputs[1].default_value = "" # Factor
point_scale_2.inputs[2].default_value = mathutils.Vector(
(0.079, 0.079, 0.079)
) # Factor
point_scale_2.inputs[3].default_value = 1.0 # Factor
return point_scale_2
def gen_transform_3(context, node_tree):
transform_3 = node_tree.nodes.new(type="GeometryNodeTransform")
# Attributes
# transform_3.label = ""
transform_3.name = "Transform"
transform_3.location = mathutils.Vector((-128.904, 46.269))
# Input Socket
transform_3.inputs["Translation"].default_value = mathutils.Vector((0.0, 0.0, 0.0))
transform_3.inputs["Rotation"].default_value = mathutils.Euler((0.0, 0.0, 0.0))
transform_3.inputs["Scale"].default_value = mathutils.Vector((1.0, 1.0, 1.0))
return transform_3
def gen_combine_xyz_4(context, node_tree):
combine_xyz_4 = node_tree.nodes.new(type="ShaderNodeCombineXYZ")
# Attributes
# combine_xyz_4.label = ""
combine_xyz_4.name = "Combine XYZ"
combine_xyz_4.location = mathutils.Vector((-473.359, -274.076))
# Input Socket
combine_xyz_4.inputs["X"].default_value = 0.0
combine_xyz_4.inputs["Y"].default_value = 0.0
combine_xyz_4.inputs["Z"].default_value = 0.0
return combine_xyz_4
def gen_value_5(context, node_tree):
value_5 = node_tree.nodes.new(type="ShaderNodeValue")
# Attributes
# value_5.label = ""
value_5.name = "Value"
value_5.location = mathutils.Vector((-1030.785, -247.654))
value_5.outputs[0].default_value = 1
value_5.outputs[0].keyframe_insert("default_value", frame=1)
value_5.outputs[0].default_value = context["frame_count"]
value_5.outputs[0].keyframe_insert(
"default_value", frame=context["frame_count_loop"]
)
# Input Socket
return value_5
def gen_map_range_6(context, node_tree):
map_range_6 = node_tree.nodes.new(type="ShaderNodeMapRange")
# Attributes
map_range_6.location = mathutils.Vector((-773.472, -244.256))
# map_range_6.label = ""
map_range_6.clamp = False
map_range_6.interpolation_type = "LINEAR"
map_range_6.name = "Map Range"
# Input Socket
map_range_6.inputs["Value"].default_value = 1.0
map_range_6.inputs["From Min"].default_value = 0.0
map_range_6.inputs["From Max"].default_value = 179.0
map_range_6.inputs["To Min"].default_value = 0.0
map_range_6.inputs["To Max"].default_value = 6.283
map_range_6.inputs["Steps"].default_value = 4.0
return map_range_6
def gen_geo_nodes_brush(context):
bpy.ops.object.modifier_add(type="NODES")
node_tree = bpy.data.node_groups["Geometry Nodes"]
node_tree.nodes["Group Input"]
node_tree.nodes["Group Output"]
gen_point_distribute_0(context, node_tree)
gen_point_instance_1(context, node_tree)
gen_point_scale_2(context, node_tree)
gen_transform_3(context, node_tree)
gen_combine_xyz_4(context, node_tree)
gen_value_5(context, node_tree)
gen_map_range_6(context, node_tree)
# links
from_node = node_tree.nodes.get("Group Input")
to_node = node_tree.nodes.get("Point Distribute")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs["Geometry"])
from_node = node_tree.nodes.get("Point Distribute")
to_node = node_tree.nodes.get("Point Scale")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs["Geometry"])
from_node = node_tree.nodes.get("Point Instance")
to_node = node_tree.nodes.get("Group Output")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs[0])
from_node = node_tree.nodes.get("Point Scale")
to_node = node_tree.nodes.get("Transform")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs["Geometry"])
from_node = node_tree.nodes.get("Transform")
to_node = node_tree.nodes.get("Point Instance")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs["Geometry"])
from_node = node_tree.nodes.get("Combine XYZ")
to_node = node_tree.nodes.get("Transform")
node_tree.links.new(from_node.outputs["Vector"], to_node.inputs["Rotation"])
from_node = node_tree.nodes.get("Value")
to_node = node_tree.nodes.get("Map Range")
node_tree.links.new(from_node.outputs["Value"], to_node.inputs["Value"])
from_node = node_tree.nodes.get("Map Range")
to_node = node_tree.nodes.get("Combine XYZ")
node_tree.links.new(from_node.outputs["Result"], to_node.inputs["X"])
make_node_tree_fcurves_linear(node_tree)
def gen_sphere_canvas(context):
canvas = add_ico_sphere(subdivisions=5)
canvas.name = "canvas"
mat, nodes = gen_mat_canvas(True)
color1 = get_random_pallet_color(context)
color2 = get_random_pallet_color(context)
nodes["ColorRamp"].color_ramp.elements[0].color = color1
nodes["ColorRamp"].color_ramp.elements[1].color = color2
nodes["ColorRamp.001"].color_ramp.elements[0].color = color2
nodes["ColorRamp.001"].color_ramp.elements[1].color = color1
apply_mat(mat)
bpy.ops.object.modifier_add(type="SUBSURF")
bpy.context.object.modifiers["Subdivision"].levels = 2
bpy.ops.object.modifier_add(type="DYNAMIC_PAINT")
bpy.ops.dpaint.type_toggle(type="CANVAS")
bpy.ops.dpaint.output_toggle(output="A")
bpy.ops.dpaint.output_toggle(output="B")
dpaint = bpy.context.object.modifiers["Dynamic Paint"]
canvas = dpaint.canvas_settings.canvas_surfaces["Surface"]
canvas.frame_start = 1
canvas.frame_end = context["frame_count"]
canvas.dry_speed = context["frame_count"] / 2
gen_geo_nodes_canvas(context)
def gen_attribute_vector_math_7(context, node_tree):
attribute_vector_math_7 = node_tree.nodes.new(
type="GeometryNodeAttributeVectorMath"
)
# Attributes
attribute_vector_math_7.input_type_c = "ATTRIBUTE"
attribute_vector_math_7.input_type_b = "ATTRIBUTE"
attribute_vector_math_7.input_type_a = "ATTRIBUTE"
attribute_vector_math_7.location = mathutils.Vector((-151.983, 95.207))
attribute_vector_math_7.name = "Attribute Vector Math"
attribute_vector_math_7.operation = "ADD"
# Input Socket
attribute_vector_math_7.inputs[1].default_value = "position" # A
attribute_vector_math_7.inputs[3].default_value = "wetmap_dsip" # B
attribute_vector_math_7.inputs[6].default_value = "" # C
attribute_vector_math_7.inputs["Result"].default_value = "position"
return attribute_vector_math_7
def gen_attribute_vector_math_8(context, node_tree):
attribute_vector_math_001_8 = node_tree.nodes.new(
type="GeometryNodeAttributeVectorMath"
)
# Attributes
attribute_vector_math_001_8.input_type_c = "ATTRIBUTE"
attribute_vector_math_001_8.input_type_b = "ATTRIBUTE"
attribute_vector_math_001_8.input_type_a = "ATTRIBUTE"
attribute_vector_math_001_8.location = mathutils.Vector((-497.432, 98.182))
attribute_vector_math_001_8.name = "Attribute Vector Math.001"
attribute_vector_math_001_8.operation = "MULTIPLY"
# Input Socket
attribute_vector_math_001_8.inputs[1].default_value = "normal" # A
attribute_vector_math_001_8.inputs[3].default_value = "wetmap_dsip" # B
attribute_vector_math_001_8.inputs[6].default_value = "" # C
attribute_vector_math_001_8.inputs["Result"].default_value = "wetmap_dsip"
return attribute_vector_math_001_8
def gen_attribute_color_ramp_9(context, node_tree):
attribute_color_ramp_9 = node_tree.nodes.new(type="GeometryNodeAttributeColorRamp")
# Attributes
attribute_color_ramp_9.name = "Attribute Color Ramp"
attribute_color_ramp_9.location = mathutils.Vector((-1037.432, 97.897))
attribute_color_ramp_9.color_ramp.elements[1].position = 0.824
# Input Socket
attribute_color_ramp_9.inputs[1].default_value = "dp_wetmap"
attribute_color_ramp_9.inputs[2].default_value = "dp_wetmap"
attribute_color_ramp_9.inputs["Attribute"].default_value = "dp_wetmap"
attribute_color_ramp_9.inputs["Result"].default_value = "dp_wetmap"
return attribute_color_ramp_9
def gen_attribute_math_10(context, node_tree):
attribute_math_10 = node_tree.nodes.new(type="GeometryNodeAttributeMath")
# Attributes
attribute_math_10.input_type_c = "ATTRIBUTE"
attribute_math_10.input_type_b = "FLOAT"
attribute_math_10.input_type_a = "ATTRIBUTE"
attribute_math_10.location = mathutils.Vector((-717.432, 70.917))
attribute_math_10.label = ""
attribute_math_10.name = "Attribute Math"
attribute_math_10.operation = "MULTIPLY"
# Input Socket
attribute_math_10.inputs[1].default_value = "dp_wetmap" # A
attribute_math_10.inputs[4].default_value = -0.199 # B
attribute_math_10.inputs[6].default_value = 0.0 # C
attribute_math_10.inputs["Result"].default_value = "wetmap_dsip"
return attribute_math_10
def gen_geo_nodes_canvas(context):
bpy.ops.object.modifier_add(type="NODES")
node_tree = bpy.data.node_groups["Geometry Nodes.001"]
node_tree.nodes["Group Input"]
node_tree.nodes["Group Output"]
gen_attribute_vector_math_7(context, node_tree)
gen_attribute_vector_math_8(context, node_tree)
gen_attribute_color_ramp_9(context, node_tree)
gen_attribute_math_10(context, node_tree)
# links begin
from_node = node_tree.nodes.get("Group Input")
to_node = node_tree.nodes.get("Attribute Color Ramp")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs["Geometry"])
from_node = node_tree.nodes.get("Attribute Vector Math")
to_node = node_tree.nodes.get("Group Output")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs[0])
from_node = node_tree.nodes.get("Attribute Vector Math.001")
to_node = node_tree.nodes.get("Attribute Vector Math")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs["Geometry"])
from_node = node_tree.nodes.get("Attribute Color Ramp")
to_node = node_tree.nodes.get("Attribute Math")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs["Geometry"])
from_node = node_tree.nodes.get("Attribute Math")
to_node = node_tree.nodes.get("Attribute Vector Math.001")
node_tree.links.new(from_node.outputs["Geometry"], to_node.inputs["Geometry"])
def gen_center_piece(context):
gen_sphere_brush(context)
gen_sphere_canvas(context)
def gen_scene(context):
add_lights_rig(context)
gen_center_piece(context)
def main():
"""
Dynamic Paint gotchas:
1. Make sure to save to a blend file before baking
(if you don't do this the Dynamic Paint modifications won't appear on the rendered frames)
2. If you have a Subdivision modifier make sure the Render and Viewport levels are the same
(You will be auto baking with the viewport level setting, so when you try to render a frame
the Subdivision level should be the same)
Tip: uncomment `bpy.ops.ptcache.bake_all(bake=True)` to automaticall bake after the script creates the scene
"""
fps = 30
# bake dynamic paint from frame 1
# render from frame 181
loop_sec = 6 * 2
frame_count = fps * loop_sec
seed = 1630964123.943
if seed:
random.seed(seed)
else:
seed = time_seed()
delete_all_objects()
setup_camera()
context = {
"frame_count": frame_count,
"frame_count_loop": frame_count + 1,
"seed": seed,
}
context["colors"] = get_color_palette()
set_scene_props(context, fps, loop_sec)
context["martial_metal"], nodes = gen_martial_metal(True)
nodes["Principled BSDF"].inputs[0].default_value = get_random_pallet_color(context)
bpy.ops.ptcache.free_bake_all()
gen_scene(context)
bpy.context.scene.eevee.taa_render_samples = 64
bpy.context.scene.render.image_settings.file_format = "PNG"
scene_num = 1
day = "283"
bpy.context.scene.render.filepath = f"/tmp/day{day}_{scene_num}/"
bpy.context.scene.view_settings.look = "Very High Contrast"
# TODO: uncomment this to bake the Dynamic Paint (Note: The baking progress is not shown )
# bpy.ops.ptcache.bake_all(bake=True)
bpy.context.scene.frame_start = context["frame_count"] / 2 + 1
def gen_mat_canvas(return_nodes=False):
mat = bpy.data.materials.new(name="Material_gen_canvas")
mat.use_nodes = True
mat_output = None
to_rm = []
for node in mat.node_tree.nodes:
if node.type == "OUTPUT_MATERIAL":
mat_output = node
continue
to_rm.append(node)
for node in to_rm:
print("Removing", node.name)
mat.node_tree.nodes.remove(node)
node_dict = dict()
mat_output.location = mathutils.Vector((346.016, 300.0))
node_1_mapping = mat.node_tree.nodes.new(type="ShaderNodeMapping")
node_1_mapping.location = mathutils.Vector((-1531.177, -63.872))
node_1_mapping.name = "Mapping"
node_1_mapping.label = ""
node_dict["Mapping"] = node_1_mapping
node_1_mapping.inputs["Vector"].default_value = (0.0, 0.0, 0.0)
node_1_mapping.inputs["Location"].default_value = mathutils.Vector((0.0, 0.0, 0.0))
node_1_mapping.inputs["Rotation"].default_value = mathutils.Euler((0.0, 0.0, 0.0))
node_1_mapping.inputs["Scale"].default_value = mathutils.Vector((1.0, 1.0, 1.0))
node_1_mapping.active_preview = False
node_1_mapping.vector_type = "POINT"
node_2_tex_coord = mat.node_tree.nodes.new(type="ShaderNodeTexCoord")
node_2_tex_coord.location = mathutils.Vector((-1741.177, -80.872))
node_2_tex_coord.name = "Texture Coordinate"
node_2_tex_coord.label = ""
node_dict["Texture Coordinate"] = node_2_tex_coord
node_2_tex_coord.active_preview = False
node_3_tex_noise = mat.node_tree.nodes.new(type="ShaderNodeTexNoise")
node_3_tex_noise.location = mathutils.Vector((-1241.177, -47.491))
node_3_tex_noise.name = "Noise Texture"
node_3_tex_noise.label = ""
node_dict["Noise Texture"] = node_3_tex_noise
node_3_tex_noise.inputs["Vector"].default_value = (0.0, 0.0, 0.0)
node_3_tex_noise.active_preview = False
node_3_tex_noise.noise_dimensions = "3D"
node_4_val_to_rgb = mat.node_tree.nodes.new(type="ShaderNodeValToRGB")
node_4_val_to_rgb.location = mathutils.Vector((-691.556, -27.459))
node_4_val_to_rgb.name = "ColorRamp"
node_4_val_to_rgb.label = ""
node_dict["ColorRamp"] = node_4_val_to_rgb
node_4_val_to_rgb.color_ramp.elements[0].color = (
0.503,
0.120,
0.171,
0.995,
)
node_4_val_to_rgb.color_ramp.elements[0].position = 0.495
node_4_val_to_rgb.color_ramp.elements[1].color = (
0.550,
0.108,
0.125,
0.995,
)
node_4_val_to_rgb.color_ramp.elements[1].position = 0.532
node_4_val_to_rgb.color_ramp.interpolation = "LINEAR"
node_4_val_to_rgb.active_preview = False
node_5_bsdf_principled = mat.node_tree.nodes.new(type="ShaderNodeBsdfPrincipled")
node_5_bsdf_principled.location = mathutils.Vector((-296.040, -596.632))
node_5_bsdf_principled.name = "Principled BSDF.001"
node_5_bsdf_principled.label = ""
node_dict["Principled BSDF.001"] = node_5_bsdf_principled
node_5_bsdf_principled.inputs["Base Color"].default_value = (
0.800,
0.800,
0.800,
1.0,
)
node_5_bsdf_principled.inputs["Subsurface Radius"].default_value = (
1.0,
0.200,
0.100,
)
node_5_bsdf_principled.inputs["Subsurface Color"].default_value = (
0.800,
0.800,
0.800,
1.0,
)
node_5_bsdf_principled.inputs["Clearcoat Roughness"].default_value = 0.028
node_5_bsdf_principled.inputs["Emission"].default_value = (
0.0,
0.0,
0.0,
1.0,
)
node_5_bsdf_principled.inputs["Normal"].default_value = (0.0, 0.0, 0.0)
node_5_bsdf_principled.inputs["Clearcoat Normal"].default_value = (
0.0,
0.0,
0.0,
)
node_5_bsdf_principled.inputs["Tangent"].default_value = (0.0, 0.0, 0.0)
node_5_bsdf_principled.subsurface_method = "BURLEY"
node_5_bsdf_principled.distribution = "GGX"
node_5_bsdf_principled.active_preview = False
node_6_val_to_rgb = mat.node_tree.nodes.new(type="ShaderNodeValToRGB")
node_6_val_to_rgb.location = mathutils.Vector((-692.838, -670.351))
node_6_val_to_rgb.name = "ColorRamp.001"
node_6_val_to_rgb.label = ""
node_dict["ColorRamp.001"] = node_6_val_to_rgb
node_6_val_to_rgb.color_ramp.elements[0].color = (
0.550,
0.108,
0.125,
0.995,
)
node_6_val_to_rgb.color_ramp.elements[0].position = 0.495
node_6_val_to_rgb.color_ramp.elements[1].color = (
0.503,
0.120,
0.171,
0.995,
)
node_6_val_to_rgb.color_ramp.elements[1].position = 0.532
node_6_val_to_rgb.color_ramp.interpolation = "LINEAR"
node_6_val_to_rgb.active_preview = False
node_7_vertex_color = mat.node_tree.nodes.new(type="ShaderNodeVertexColor")
node_7_vertex_color.location = mathutils.Vector((-810.627, 277.311))
node_7_vertex_color.name = "Vertex Color"
node_7_vertex_color.label = ""
node_dict["Vertex Color"] = node_7_vertex_color
node_7_vertex_color.active_preview = False
node_7_vertex_color.layer_name = "dp_wetmap"
node_8_val_to_rgb = mat.node_tree.nodes.new(type="ShaderNodeValToRGB")
node_8_val_to_rgb.location = mathutils.Vector((-431.062, 263.834))
node_8_val_to_rgb.name = "ColorRamp.002"
node_8_val_to_rgb.label = ""
node_dict["ColorRamp.002"] = node_8_val_to_rgb
node_8_val_to_rgb.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
node_8_val_to_rgb.color_ramp.elements[0].position = 0.0
node_8_val_to_rgb.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
node_8_val_to_rgb.color_ramp.elements[1].position = 0.081
node_8_val_to_rgb.color_ramp.interpolation = "LINEAR"
node_8_val_to_rgb.active_preview = False
node_9_mix_shader = mat.node_tree.nodes.new(type="ShaderNodeMixShader")
node_9_mix_shader.location = mathutils.Vector((61.969, 241.682))
node_9_mix_shader.name = "Mix Shader"
node_9_mix_shader.label = ""
node_dict["Mix Shader"] = node_9_mix_shader
node_9_mix_shader.active_preview = False
bsdf = mat.node_tree.nodes.new(type="ShaderNodeBsdfPrincipled")
bsdf.location = mathutils.Vector((-294.757, 46.257))
bsdf.name = "Principled BSDF"
bsdf.label = ""
node_dict["Principled BSDF"] = bsdf
bsdf.inputs["Base Color"].default_value = (
0.800,
0.800,
0.800,
1.0,
)
bsdf.inputs["Subsurface Radius"].default_value = (
1.0,
0.200,
0.100,
)
bsdf.inputs["Subsurface Color"].default_value = (
0.800,
0.800,
0.800,
1.0,
)
bsdf.inputs["Clearcoat Roughness"].default_value = 0.028
bsdf.inputs["Emission"].default_value = (
0.0,
0.0,
0.0,
1.0,
)
bsdf.inputs["Normal"].default_value = (0.0, 0.0, 0.0)
bsdf.inputs["Clearcoat Normal"].default_value = (
0.0,
0.0,
0.0,
)
bsdf.inputs["Tangent"].default_value = (0.0, 0.0, 0.0)
bsdf.subsurface_method = "BURLEY"
bsdf.distribution = "GGX"
bsdf.active_preview = False
node_11ShaderNodeTexVoronoi = mat.node_tree.nodes.new(type="ShaderNodeTexVoronoi")
node_11ShaderNodeTexVoronoi.location = mathutils.Vector((-949.015, -36.187))
node_11ShaderNodeTexVoronoi.name = "Voronoi Texture"
node_11ShaderNodeTexVoronoi.label = ""
node_dict["Voronoi Texture"] = node_11ShaderNodeTexVoronoi
node_11ShaderNodeTexVoronoi.inputs["Vector"].default_value = (0.0, 0.0, 0.0)
node_11ShaderNodeTexVoronoi.inputs["Randomness"].default_value = 0.0
node_11ShaderNodeTexVoronoi.distance = "CHEBYCHEV"
node_11ShaderNodeTexVoronoi.voronoi_dimensions = "3D"
node_11ShaderNodeTexVoronoi.feature = "F2"
node_11ShaderNodeTexVoronoi.active_preview = False
# links
from_node = mat.node_tree.nodes.get("Vertex Color")
to_node = mat.node_tree.nodes.get("ColorRamp.002")
mat.node_tree.links.new(from_node.outputs["Color"], to_node.inputs["Fac"])
from_node = mat.node_tree.nodes.get("Mapping")
to_node = mat.node_tree.nodes.get("Noise Texture")
mat.node_tree.links.new(from_node.outputs["Vector"], to_node.inputs["Vector"])
from_node = mat.node_tree.nodes.get("Texture Coordinate")
to_node = mat.node_tree.nodes.get("Mapping")
mat.node_tree.links.new(from_node.outputs["Generated"], to_node.inputs["Vector"])
from_node = mat.node_tree.nodes.get("Noise Texture")
to_node = mat.node_tree.nodes.get("Voronoi Texture")
mat.node_tree.links.new(from_node.outputs["Color"], to_node.inputs["Vector"])
from_node = mat.node_tree.nodes.get("ColorRamp")
to_node = mat.node_tree.nodes.get("Principled BSDF")
mat.node_tree.links.new(from_node.outputs["Color"], to_node.inputs["Base Color"])
from_node = mat.node_tree.nodes.get("ColorRamp")
to_node = mat.node_tree.nodes.get("Principled BSDF")
mat.node_tree.links.new(from_node.outputs["Color"], to_node.inputs["Roughness"])
from_node = mat.node_tree.nodes.get("ColorRamp.001")
to_node = mat.node_tree.nodes.get("Principled BSDF.001")
mat.node_tree.links.new(from_node.outputs["Color"], to_node.inputs["Base Color"])
from_node = mat.node_tree.nodes.get("ColorRamp.001")
to_node = mat.node_tree.nodes.get("Principled BSDF.001")
mat.node_tree.links.new(from_node.outputs["Color"], to_node.inputs["Roughness"])
from_node = mat.node_tree.nodes.get("Voronoi Texture")
to_node = mat.node_tree.nodes.get("ColorRamp.001")
mat.node_tree.links.new(from_node.outputs["Distance"], to_node.inputs["Fac"])
from_node = mat.node_tree.nodes.get("Principled BSDF.001")
to_node = mat.node_tree.nodes.get("Mix Shader")
mat.node_tree.links.new(from_node.outputs["BSDF"], to_node.inputs["Shader"])
from_node = mat.node_tree.nodes.get("ColorRamp.002")
to_node = mat.node_tree.nodes.get("Mix Shader")
mat.node_tree.links.new(from_node.outputs["Color"], to_node.inputs["Fac"])
from_node = mat.node_tree.nodes.get("Mix Shader")
to_node = mat.node_tree.nodes.get("Material Output")
mat.node_tree.links.new(from_node.outputs["Shader"], to_node.inputs["Surface"])
from_node = mat.node_tree.nodes.get("Principled BSDF")
to_node = mat.node_tree.nodes.get("Mix Shader")
mat.node_tree.links.new(from_node.outputs["BSDF"], to_node.inputs[2])
from_node = mat.node_tree.nodes.get("Voronoi Texture")
to_node = mat.node_tree.nodes.get("ColorRamp")
mat.node_tree.links.new(from_node.outputs["Distance"], to_node.inputs["Fac"])
if return_nodes:
return mat, node_dict
else:
return mat
def gen_martial_metal(return_nodes=False):
mat = bpy.data.materials.new(name="Material_gen_metal")
mat.use_nodes = True
mat_output = None
to_rm = []
for node in mat.node_tree.nodes:
if node.type == "OUTPUT_MATERIAL":
mat_output = node
continue
to_rm.append(node)
for node in to_rm:
mat.node_tree.nodes.remove(node)
node_dict = dict()
mat_output.location = mathutils.Vector((300.0, 300.0))
bsdf = mat.node_tree.nodes.new(type="ShaderNodeBsdfPrincipled")
bsdf.location = mathutils.Vector((10.0, 300.0))
bsdf.name = "Principled BSDF"
bsdf.label = ""
node_dict["Principled BSDF"] = bsdf
bsdf.inputs["Base Color"].default_value = (
0.925,
0.882,
0.777,
0.996,
)
bsdf.inputs["Subsurface Radius"].default_value = (
1.0,
0.200,
0.100,
)
bsdf.inputs["Subsurface Color"].default_value = (
0.800,
0.800,
0.800,
1.0,
)
bsdf.inputs["Metallic"].default_value = 0.996
bsdf.inputs["Roughness"].default_value = 0.245
bsdf.inputs["Emission"].default_value = (
0.0,
0.0,
0.0,
1.0,
)
bsdf.inputs["Normal"].default_value = (0.0, 0.0, 0.0)
bsdf.inputs["Clearcoat Normal"].default_value = (
0.0,
0.0,
0.0,
)
bsdf.inputs["Tangent"].default_value = (0.0, 0.0, 0.0)
bsdf.distribution = "GGX"
bsdf.active_preview = False
bsdf.subsurface_method = "BURLEY"
from_node = mat.node_tree.nodes.get("Principled BSDF")
to_node = mat.node_tree.nodes.get("Material Output")
mat.node_tree.links.new(from_node.outputs["BSDF"], to_node.inputs["Surface"])
if return_nodes:
return mat, node_dict
else:
return mat
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment