Created
May 29, 2018 23:07
-
-
Save behreajj/87b0a32fce01e78d3351b6862c797ade to your computer and use it in GitHub Desktop.
Sampler Full
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
from math import cos, sin, fmod | |
from random import TWOPI | |
def append_group_inst(nodes, group_name, data=bpy.data, group_creation_func=None, use_fake_user=False, parent=None, custom_color=None): | |
group = None | |
try: | |
group = data.node_groups[group_name] | |
except IndexError: | |
if group_creation_func: | |
group = group_creation_func(data, use_fake_user) | |
if group: | |
gp_in = nodes.new('ShaderNodeGroup') | |
gp_in.node_tree = group | |
gp_in.name = group_name | |
gp_in.parent = parent | |
if custom_color: | |
gp_in.use_custom_color = True | |
gp_in.color = custom_color | |
return gp_in | |
else: | |
return None | |
def append_ring_inst(nodes, data=bpy.data, scene=bpy.context.scene, group_creation_func=None, use_fake_user=False, point={0: (0.0, 0.0, 0.0)}, center_outer={0: (0.5, 0.5, 0.5)}, center_inner={0: (0.5, 0.5, 0.5)}, background={0: (0.0, 0.0, 0.0, 1.0)}, fill={0: (0.214041, 0.214041, 0.214041, 1.0)}, stroke={0: (1.0, 1.0, 1.0, 1.0)}, margin={0: 0.05}, tiles={0: 1}, scale={0: 0.625}, stroke_weight={0: 0.05}, parent=None, custom_color=None): | |
ring_inst = append_group_inst(nodes=nodes, group_name='Ring', data=data, group_creation_func=group_creation_func, use_fake_user=use_fake_user, parent=parent, custom_color=custom_color) | |
anim_node_inputs(input_ref=ring_inst.inputs, args={ | |
'Point': point, | |
'Center Outer': center_outer, | |
'Center Inner': center_inner, | |
'Background': background, | |
'Fill': fill, | |
'Stroke': stroke, | |
'Margin': margin, | |
'Tiles': tiles, | |
'Scale': scale, | |
'Stroke Weight': stroke_weight | |
}, scene=scene) | |
return ring_inst | |
def append_absorb_inst(nodes, data=bpy.data, scene=bpy.context.scene, group_creation_func=None, use_fake_user=False, colors={0: (0.02, 0.02, 0.02, 1.0)}, densities={0: 12.0}, factors={0: 0.5}, lowers={0: 0.0}, uppers={0: 1.0}, parent=None, custom_color=None): | |
absorb_inst = append_group_inst(nodes=nodes, group_name='Shaped Absorb', data=data, group_creation_func=group_creation_func, use_fake_user=use_fake_user, parent=parent, custom_color=custom_color) | |
anim_node_inputs(input_ref=absorb_inst.inputs, args={ | |
'Color': colors, | |
'Density': densities, | |
'Fac': factors, | |
'Lower': lowers, | |
'Upper': uppers}, scene=scene) | |
return absorb_inst | |
def append_light_inst(nodes, data=bpy.data, scene=bpy.context.scene, group_creation_func=None, use_fake_user=False, temps={0: 1500.0}, strengths={0: 1.0}, factors={0: 0.5}, lowers={0: 0.0}, uppers={0: 1.0}, parent=None, custom_color=None): | |
light_inst = append_group_inst(nodes=nodes, group_name='Shaped Light', data=data, group_creation_func=group_creation_func, use_fake_user=use_fake_user, parent=parent, custom_color=custom_color) | |
anim_node_inputs(input_ref=light_inst.inputs, args={ | |
'Temperature': temps, | |
'Strength': strengths, | |
'Fac': factors, | |
'Lower': lowers, | |
'Upper': uppers}, scene=scene) | |
return light_inst | |
def append_map_inst(nodes, data=bpy.data, scene=bpy.context.scene, group_creation_func=None, use_fake_user=False, origin_value={0: 0.0}, origin_lb={0: -1.0}, origin_ub={0: 1.0}, target_lb={0: 0.0}, target_ub={0: 1.0}, parent=None, custom_color=None): | |
map_inst = append_group_inst(nodes=nodes, group_name='Map', data=data, group_creation_func=group_creation_func, use_fake_user=use_fake_user, parent=parent, custom_color=custom_color) | |
anim_node_inputs(input_ref=map_inst.inputs, args={ | |
'Origin Value': origin_value, | |
'Origin Lower Bound': origin_lb, | |
'Origin Upper Bound': origin_ub, | |
'Target Lower Bound': target_lb, | |
'Target Upper Bound': target_ub, | |
}, scene=scene) | |
return map_inst | |
def append_rotate_z_inst(nodes, data=bpy.data, scene=bpy.context.scene, group_creation_func=None, use_fake_user=False, radians={0: 0.0}, vector={0: (0.0, 0.0, 0.0)}, pivot={0: (0.0, 0.0, 0.0)}, parent=None, custom_color=None): | |
rotate_z_inst = append_group_inst(nodes=nodes, group_name='RotateZ', data=data, group_creation_func=group_creation_func, use_fake_user=use_fake_user, parent=parent, custom_color=custom_color) | |
anim_node_inputs(input_ref=rotate_z_inst.inputs, args={ | |
'Radians': radians, | |
'Vector': vector, | |
'Pivot': pivot | |
}, scene=scene) | |
return rotate_z_inst | |
def append_txtr_coord(nodes, obj=None, parent=None, custom_color=None): | |
txtr_coord = nodes.new('ShaderNodeTexCoord') | |
txtr_coord.object = obj | |
txtr_coord.parent = parent | |
if custom_color: | |
txtr_coord.use_custom_color = True | |
txtr_coord.color = custom_color | |
return txtr_coord | |
def float_lerp(a=0.0, b=1.0, t=0.5): | |
return (1.0 - t) * a + t * b | |
def anim_node_inputs(input_ref, args, scene=bpy.context.scene): | |
# Gather list of entries from args dictionary. | |
args_entries = args.items() | |
for arg_entry in args_entries: | |
name = arg_entry[0] # Key | |
frames = arg_entry[1] # Value | |
# Attempt to get the appropriate socket by name. | |
in_socket = input_ref.get(name) | |
if in_socket: | |
# Gather list of entries from frames dictionary. | |
frame_entries = frames.items() | |
length = len(frame_entries) | |
for frame_entry in frame_entries: | |
frame = frame_entry[0] # Key | |
default = frame_entry[1] # Value | |
scene.frame_current = frame | |
in_socket.default_value = default | |
if length > 1: | |
in_socket.keyframe_insert(data_path='default_value') | |
return input_ref | |
def append_vec_mult_inst(nodes, data=bpy.data, scene=bpy.context.scene, group_creation_func=None, use_fake_user=False, vector={0: (0.0, 0.0, 0.0)}, scalar={0: 1.0}, parent=None, custom_color=None): | |
vec_mult_inst = append_group_inst(nodes=nodes, group_name='Vector Mult', data=data, group_creation_func=group_creation_func, use_fake_user=use_fake_user, parent=parent, custom_color=custom_color) | |
anim_node_inputs(input_ref=vec_mult_inst, args={'Vector': vector, 'Scalar': scalar}, scene=scene) | |
return vec_mult_inst | |
def append_noise_txtr(nodes, scene=bpy.context.scene, scales={0: 5.0}, details={0: 2.0}, distortions={0: 0.0}, parent=None, custom_color=None): | |
noise_txtr = nodes.new('ShaderNodeTexNoise') | |
noise_txtr.parent = parent | |
if custom_color: | |
noise_txtr.use_custom_color = True | |
noise_txtr.color = custom_color | |
anim_node_inputs(input_ref=noise_txtr.inputs, args={'Scale': scales, 'Detail': details, 'Distortion': distortions}, scene=scene) | |
return noise_txtr | |
def append_voronoi_txtr(nodes, scene=bpy.context.scene, coloring='INTENSITY', scales={0: 5.0}, parent=None, custom_color=None): | |
vor_txtr = nodes.new('ShaderNodeTexVoronoi') | |
vor_txtr.coloring = coloring | |
vor_txtr.parent = parent | |
if custom_color: | |
vor_txtr.use_custom_color = True | |
vor_txtr.color = custom_color | |
anim_node_inputs(input_ref=vor_txtr.inputs, args={'Scale': scales}, scene=scene) | |
return vor_txtr | |
def append_comb_hsv(nodes, scene=bpy.context.scene, h={0: 0.0}, s={0: 0.0}, v={0: 1.0}, parent=None, custom_color=None): | |
hsv = nodes.new('ShaderNodeCombineHSV') | |
hsv.parent = parent | |
if custom_color: | |
hsv.use_custom_color = True | |
hsv.color = custom_color | |
anim_node_inputs(input_ref=hsv.inputs, args={'H': h, 'S': s, 'V': v}, scene=scene) | |
return hsv | |
def append_pbr_node(nodes, scene=bpy.context.scene, distribution='MULTI_GGX', base_color={0: (1.0, 1.0, 1.0, 1.0)}, subsurface={0: 0.0}, subsurface_radius={0: (1.0, 1.0, 1.0)}, subsurface_color={0: (0.7, 0.1, 0.1, 1.0)}, metallic={0: 0.0}, specular={0: 0.5}, specular_tint={0: 0.0}, roughness={0: 0.5}, anisotropic={0: 0.0}, anisotropic_rotation={0: 0.0}, sheen={0: 0.0}, sheen_tint={0: 0.5}, clearcoat={0: 0.0}, clearcoat_roughness={0: 0.3}, ior={0: 1.45}, transmission={0: 0.0}, parent=None, custom_color=None): | |
pbr = nodes.new('ShaderNodeBsdfPrincipled') | |
pbr.parent = parent | |
if custom_color: | |
pbr.use_custom_color = True | |
pbr.color = custom_color | |
# Set distribution. Choices are 'GGX' and 'MULTI_GGX'. | |
pbr.distribution = distribution | |
anim_node_inputs(input_ref=pbr.inputs, args={ | |
'Base Color': base_color, | |
'Subsurface': subsurface, | |
'Subsurface Radius': subsurface_radius, | |
'Subsurface Color': subsurface_color, | |
'Metallic': metallic, | |
'Specular': specular, | |
'Specular Tint': specular_tint, | |
'Roughness': roughness, | |
'Anisotropic': anisotropic, | |
'Anisotropic Rotation': anisotropic_rotation, | |
'Sheen': sheen, | |
'Sheen Tint': sheen_tint, | |
'Clearcoat': clearcoat, | |
'Clearcoat Roughness': clearcoat_roughness, | |
'IOR': ior, | |
'Transmission': transmission}, scene=scene) | |
return pbr | |
def init_pbr_mat(data=bpy.data, scene=bpy.context.scene, obj=bpy.context.active_object, name='Material', distribution='MULTI_GGX', base_color={0: (1.0, 1.0, 1.0, 1.0)}, subsurface={0: 0.0}, subsurface_radius={0: (1.0, 1.0, 1.0)}, subsurface_color={0: (0.7, 0.1, 0.1, 1.0)}, metallic={0: 0.0}, specular={0: 0.5}, specular_tint={0: 0.0}, roughness={0: 0.5}, anisotropic={0: 0.0}, anisotropic_rotation={0: 0.0}, sheen={0: 0.0}, sheen_tint={0: 0.5}, clearcoat={0: 0.0}, clearcoat_roughness={0: 0.3}, ior={0: 1.45}, transmission={0: 0.0}): | |
material = data.materials.new(name) | |
material.use_nodes = True | |
node_tree = material.node_tree | |
nodes = node_tree.nodes | |
# Acquire material output. If not present, create a new one. | |
mat_output = None | |
try: | |
mat_output = nodes['Material Output'] | |
except IndexError: | |
mat_output = nodes.new('ShaderNodeOutputMaterial') | |
# Delete diffuse BSDF if present. | |
try: | |
nodes.remove(nodes['Diffuse BSDF']) | |
except IndexError: | |
pass | |
# Add geometry and PBR shaders. | |
geom = nodes.new('ShaderNodeNewGeometry') | |
pbr = append_pbr_node(nodes=nodes, scene=scene, distribution=distribution, base_color=base_color, subsurface=subsurface, subsurface_radius=subsurface_radius, subsurface_color=subsurface_color, metallic=metallic, specular=specular, specular_tint=specular_tint, roughness=roughness, anisotropic=anisotropic, anisotropic_rotation=anisotropic_rotation, sheen=sheen, sheen_tint=sheen_tint, clearcoat=clearcoat, clearcoat_roughness=clearcoat_roughness, ior=ior, transmission=transmission) | |
# Link geometry and PBR shaders. | |
pbr_inputs = pbr.inputs | |
geom_outputs = geom.outputs | |
node_tree.links.new(pbr_inputs['Normal'], geom_outputs['Normal']) | |
node_tree.links.new(pbr_inputs['Clearcoat Normal'], geom_outputs['Normal']) | |
node_tree.links.new(pbr_inputs['Tangent'], geom_outputs['Tangent']) | |
node_tree.links.new(mat_output.inputs['Surface'], pbr.outputs['BSDF']) | |
return material | |
def create_sampler(data=bpy.data, context=bpy.context, ops=bpy.ops, scene=bpy.context.scene, loc=(0.0, 0.0, 0.0), name='Sampler', count=20, swatch_size=1.0, segments=48, ring_count=24, frame_start=bpy.context.scene.frame_start, frame_end=bpy.context.scene.frame_end): | |
ops.object.empty_add(type='PLAIN_AXES', location=loc) | |
sampler = context.object | |
sampler.name = name | |
inv_count_ln = 1.0 / (count - 1) | |
inv_count_rd = 1.0 / count | |
radius = count * 0.35 | |
for i in range(0, count, 1): | |
# Enter edit mode upon creation. | |
ops.mesh.primitive_uv_sphere_add(size=swatch_size, segments=segments, ring_count=ring_count, enter_editmode=True) | |
# Set UV coordinates. | |
ops.uv.sphere_project(direction='ALIGN_TO_OBJECT') | |
# Toggle back to object mode. | |
ops.object.editmode_toggle() | |
# Use smooth shading. | |
ops.object.shade_smooth() | |
# Set name and parent. | |
obj = context.object | |
obj.name = obj.data.name = '{0:0>3d}.Sample'.format(i) | |
obj.parent = sampler | |
# Set location. | |
i_percent_rd = i * inv_count_rd | |
theta = TWOPI * i_percent_rd | |
obj.location = (cos(theta) * radius, sin(theta) * radius, 0.0) | |
# Create materials. | |
mat = init_pbr_mat(obj=obj, name=obj.name, metallic={frame_start: 0.0, frame_end: 0.5}, specular={0: 0.2}, roughness={frame_start: 0.01, frame_end: 0.333}, sheen={0: 0.2}, clearcoat={0: 0.99}, clearcoat_roughness={0: 0.01}) | |
# Cache references. | |
node_tree = mat.node_tree | |
nodes = node_tree.nodes | |
# Set color. | |
i_percent_ln = i * inv_count_ln | |
comb_hsv = append_comb_hsv(nodes=nodes, scene=scene, h={0: float_lerp(1.0, 0.5, i_percent_ln)}, s={0: 1.0}, v={frame_start: 1.0, frame_end: 0.5}) | |
ring_inst = append_ring_inst(nodes=nodes, data=data, scene=scene, fill={0: (1.0, 0.95, 0.9, 1.0)}, stroke={0: (1.0, 0.75, 0.667, 1.0)}, tiles={0: 4}, margin={0: 0.1}) | |
rtz_inst = append_rotate_z_inst(nodes=nodes, data=data, scene=scene, radians={frame_start: theta, frame_end: theta + TWOPI}, pivot={0: (0.5, 0.5, 0.5)}) | |
txtr_coord = append_txtr_coord(nodes=nodes, obj=obj) | |
node_tree.links.new(nodes['Principled BSDF'].inputs['Base Color'], ring_inst.outputs['Stroke Fill']) | |
node_tree.links.new(nodes['Principled BSDF'].inputs['Roughness'], ring_inst.outputs[3]) | |
node_tree.links.new(nodes['Principled BSDF'].inputs['Metallic'], ring_inst.outputs[3]) | |
node_tree.links.new(nodes['Material Output'].inputs['Displacement'], ring_inst.outputs[3]) | |
node_tree.links.new(nodes['Principled BSDF'].inputs['Transmission'], ring_inst.outputs[4]) | |
node_tree.links.new(ring_inst.inputs['Background'], comb_hsv.outputs['Color']) | |
node_tree.links.new(ring_inst.inputs['Point'], rtz_inst.outputs['Vector']) | |
node_tree.links.new(rtz_inst.inputs['Vector'], txtr_coord.outputs['Generated']) | |
absorb_hsv = append_comb_hsv(nodes=nodes, scene=scene, h={0: float_lerp(1.0, 0.5, i_percent_ln)}, s={0: 1.0}, v={frame_start: 0.25, frame_end: 0.0}) | |
light_inst = append_light_inst(nodes=nodes, data=data, scene=scene, lowers={0: -.01}, uppers={0: 1.01}) | |
absorb_inst = append_absorb_inst(nodes=nodes, data=data, scene=scene, lowers={0: -.01}, uppers={0: 1.01}, densities={frame_start: 3.0, frame_end: 6.0}) | |
map_inst = append_map_inst(nodes=nodes, data=data, scene=scene, origin_lb={0: 0.0}, origin_ub={0: 1.0}, target_lb={0: float_lerp(800.0, 1500.0, i_percent_ln)}, target_ub={0: float_lerp(2000.0, 6000.0, i_percent_ln)}) | |
add_sh = nodes.new('ShaderNodeAddShader') | |
sep_xyz = nodes.new('ShaderNodeSeparateXYZ') | |
node_tree.links.new(sep_xyz.inputs['Vector'], rtz_inst.outputs['Vector']) | |
node_tree.links.new(map_inst.inputs['Origin Value'], sep_xyz.outputs['X']) | |
node_tree.links.new(light_inst.inputs['Temperature'], map_inst.outputs['Target Value']) | |
node_tree.links.new(add_sh.inputs[0], absorb_inst.outputs['Volume']) | |
node_tree.links.new(add_sh.inputs[1], light_inst.outputs['Emission']) | |
node_tree.links.new(nodes['Material Output'].inputs['Volume'], add_sh.outputs['Shader']) | |
node_tree.links.new(light_inst.inputs['Fac'], ring_inst.outputs[3]) | |
node_tree.links.new(absorb_inst.inputs['Fac'], ring_inst.outputs[4]) | |
node_tree.links.new(absorb_inst.inputs['Color'], absorb_hsv.outputs['Color']) | |
# NEW | |
noise = append_noise_txtr(nodes=nodes, scene=scene, scales={0: float_lerp(1.5, 3.0, i_percent_ln)}, details={0: float_lerp(2.0, 1.5, i_percent_ln)}, distortions={frame_start: 0.0, frame_end: 1.0}) | |
vor = append_voronoi_txtr(nodes=nodes, scene=scene, scales={0: float_lerp(5.0, 2.0, i_percent_ln)}) | |
vec_mult = append_vec_mult_inst(nodes=nodes, data=data, scene=scene) | |
node_tree.links.new(ring_inst.inputs['Point'], vec_mult.outputs['Vector']) | |
node_tree.links.new(vec_mult.inputs['Vector'], rtz_inst.outputs['Vector']) | |
node_tree.links.new(vec_mult.inputs['Scalar'], vor.outputs['Fac']) | |
node_tree.links.new(vor.inputs['Scale'], noise.outputs['Fac']) | |
node_tree.links.new(vor.inputs['Vector'], rtz_inst.outputs['Vector']) | |
node_tree.links.new(noise.inputs['Vector'], nodes['Geometry'].outputs['Position']) | |
# Append new material to sample. | |
obj.data.materials.append(mat) | |
return sampler | |
create_sampler() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment