Files
blender-addons/render_povray/nodes_fn.py
Campbell Barton 016430de4b Cleanup: remove <pep8 compliant> comment
This is no longer necessary, see: T98554.
2022-06-03 11:50:32 +10:00

703 lines
37 KiB
Python

# SPDX-License-Identifier: GPL-2.0-or-later
"""Translate complex shaders to exported POV textures."""
import bpy
# WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
def write_nodes(pov_mat_name, ntree, file):
"""Translate Blender node trees to pov and write them to file."""
# such function local inlined import are official guidelines
# of Blender Foundation to lighten addons footprint at startup
from os import path
from .render import string_strip_hyphen
declare_nodes = []
scene = bpy.context.scene
for node in ntree.nodes:
pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayFinishNode" and node.outputs["Finish"].is_linked:
file.write("#declare %s = finish {\n" % pov_node_name)
emission = node.inputs["Emission"].default_value
if node.inputs["Emission"].is_linked:
pass
file.write(" emission %.4g\n" % emission)
for link in ntree.links:
if link.to_node == node:
if link.from_node.bl_idname == "PovrayDiffuseNode":
intensity = 0
albedo = ""
brilliance = 0
crand = 0
if link.from_node.inputs["Intensity"].is_linked:
pass
else:
intensity = link.from_node.inputs["Intensity"].default_value
if link.from_node.inputs["Albedo"].is_linked:
pass
else:
if link.from_node.inputs["Albedo"].default_value:
albedo = "albedo"
file.write(" diffuse %s %.4g\n" % (albedo, intensity))
if link.from_node.inputs["Brilliance"].is_linked:
pass
else:
brilliance = link.from_node.inputs["Brilliance"].default_value
file.write(" brilliance %.4g\n" % brilliance)
if link.from_node.inputs["Crand"].is_linked:
pass
else:
crand = link.from_node.inputs["Crand"].default_value
if crand > 0:
file.write(" crand %.4g\n" % crand)
if link.from_node.bl_idname == "PovraySubsurfaceNode":
if scene.povray.sslt_enable:
energy = 0
r = g = b = 0
if link.from_node.inputs["Translucency"].is_linked:
pass
else:
r, g, b, a = link.from_node.inputs["Translucency"].default_value[:]
if link.from_node.inputs["Energy"].is_linked:
pass
else:
energy = link.from_node.inputs["Energy"].default_value
file.write(
" subsurface { translucency <%.4g,%.4g,%.4g>*%s }\n"
% (r, g, b, energy)
)
if link.from_node.bl_idname in {"PovraySpecularNode", "PovrayPhongNode"}:
intensity = 0
albedo = ""
roughness = 0
metallic = 0
phong_size = 0
highlight = "specular"
if link.from_node.inputs["Intensity"].is_linked:
pass
else:
intensity = link.from_node.inputs["Intensity"].default_value
if link.from_node.inputs["Albedo"].is_linked:
pass
else:
if link.from_node.inputs["Albedo"].default_value:
albedo = "albedo"
if link.from_node.bl_idname in {"PovrayPhongNode"}:
highlight = "phong"
file.write(" %s %s %.4g\n" % (highlight, albedo, intensity))
if link.from_node.bl_idname in {"PovraySpecularNode"}:
if link.from_node.inputs["Roughness"].is_linked:
pass
else:
roughness = link.from_node.inputs["Roughness"].default_value
file.write(" roughness %.6g\n" % roughness)
if link.from_node.bl_idname in {"PovrayPhongNode"}:
if link.from_node.inputs["Size"].is_linked:
pass
else:
phong_size = link.from_node.inputs["Size"].default_value
file.write(" phong_size %s\n" % phong_size)
if link.from_node.inputs["Metallic"].is_linked:
pass
else:
metallic = link.from_node.inputs["Metallic"].default_value
file.write(" metallic %.4g\n" % metallic)
if link.from_node.bl_idname in {"PovrayMirrorNode"}:
file.write(" reflection {\n")
color = None
exponent = 0
metallic = 0
falloff = 0
fresnel = ""
conserve = ""
if link.from_node.inputs["Color"].is_linked:
pass
else:
color = link.from_node.inputs["Color"].default_value[:]
file.write(" <%.4g,%.4g,%.4g>\n" % (color[0], color[1], color[2]))
if link.from_node.inputs["Exponent"].is_linked:
pass
else:
exponent = link.from_node.inputs["Exponent"].default_value
file.write(" exponent %.4g\n" % exponent)
if link.from_node.inputs["Falloff"].is_linked:
pass
else:
falloff = link.from_node.inputs["Falloff"].default_value
file.write(" falloff %.4g\n" % falloff)
if link.from_node.inputs["Metallic"].is_linked:
pass
else:
metallic = link.from_node.inputs["Metallic"].default_value
file.write(" metallic %.4g" % metallic)
if link.from_node.inputs["Fresnel"].is_linked:
pass
else:
if link.from_node.inputs["Fresnel"].default_value:
fresnel = "fresnel"
if link.from_node.inputs["Conserve energy"].is_linked:
pass
else:
if link.from_node.inputs["Conserve energy"].default_value:
conserve = "conserve_energy"
file.write(" %s}\n %s\n" % (fresnel, conserve))
if link.from_node.bl_idname == "PovrayAmbientNode":
ambient = (0, 0, 0)
if link.from_node.inputs["Ambient"].is_linked:
pass
else:
ambient = link.from_node.inputs["Ambient"].default_value[:]
file.write(" ambient <%.4g,%.4g,%.4g>\n" % ambient)
if link.from_node.bl_idname in {"PovrayIridescenceNode"}:
file.write(" irid {\n")
amount = 0
thickness = 0
turbulence = 0
if link.from_node.inputs["Amount"].is_linked:
pass
else:
amount = link.from_node.inputs["Amount"].default_value
file.write(" %.4g\n" % amount)
if link.from_node.inputs["Thickness"].is_linked:
pass
else:
exponent = link.from_node.inputs["Thickness"].default_value
file.write(" thickness %.4g\n" % thickness)
if link.from_node.inputs["Turbulence"].is_linked:
pass
else:
falloff = link.from_node.inputs["Turbulence"].default_value
file.write(" turbulence %.4g}\n" % turbulence)
file.write("}\n")
for node in ntree.nodes:
pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayTransformNode" and node.outputs["Transform"].is_linked:
tx = node.inputs["Translate x"].default_value
ty = node.inputs["Translate y"].default_value
tz = node.inputs["Translate z"].default_value
rx = node.inputs["Rotate x"].default_value
ry = node.inputs["Rotate y"].default_value
rz = node.inputs["Rotate z"].default_value
sx = node.inputs["Scale x"].default_value
sy = node.inputs["Scale y"].default_value
sz = node.inputs["Scale z"].default_value
file.write(
"#declare %s = transform {\n"
" translate<%.4g,%.4g,%.4g>\n"
" rotate<%.4g,%.4g,%.4g>\n"
" scale<%.4g,%.4g,%.4g>}\n" % (pov_node_name, tx, ty, tz, rx, ry, rz, sx, sy, sz)
)
for node in ntree.nodes:
pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayColorImageNode" and node.outputs["Pigment"].is_linked:
declare_nodes.append(node.name)
if node.image == "":
file.write("#declare %s = pigment { color rgb 0.8}\n" % pov_node_name)
else:
im = bpy.data.images[node.image]
if im.filepath and path.exists(bpy.path.abspath(im.filepath)): # (os.path)
transform = ""
for link in ntree.links:
if (
link.from_node.bl_idname == "PovrayTransformNode"
and link.to_node == node
):
pov_trans_name = (
string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ "_%s" % pov_mat_name
)
transform = "transform {%s}" % pov_trans_name
uv = ""
if node.map_type == "uv_mapping":
uv = "uv_mapping"
filepath = bpy.path.abspath(im.filepath)
file.write("#declare %s = pigment {%s image_map {\n" % (pov_node_name, uv))
premul = "off"
if node.premultiplied:
premul = "on"
once = ""
if node.once:
once = "once"
file.write(
' "%s"\n gamma %.6g\n premultiplied %s\n'
% (filepath, node.inputs["Gamma"].default_value, premul)
)
file.write(" %s\n" % once)
if node.map_type != "uv_mapping":
file.write(" map_type %s\n" % node.map_type)
file.write(
" interpolate %s\n filter all %.4g\n transmit all %.4g\n"
% (
node.interpolate,
node.inputs["Filter"].default_value,
node.inputs["Transmit"].default_value,
)
)
file.write(" }\n")
file.write(" %s\n" % transform)
file.write(" }\n")
for node in ntree.nodes:
pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayImagePatternNode" and node.outputs["Pattern"].is_linked:
declare_nodes.append(node.name)
if node.image != "":
im = bpy.data.images[node.image]
if im.filepath and path.exists(bpy.path.abspath(im.filepath)):
transform = ""
for link in ntree.links:
if (
link.from_node.bl_idname == "PovrayTransformNode"
and link.to_node == node
):
pov_trans_name = (
string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ "_%s" % pov_mat_name
)
transform = "transform {%s}" % pov_trans_name
uv = ""
if node.map_type == "uv_mapping":
uv = "uv_mapping"
filepath = bpy.path.abspath(im.filepath)
file.write("#macro %s() %s image_pattern {\n" % (pov_node_name, uv))
premul = "off"
if node.premultiplied:
premul = "on"
once = ""
if node.once:
once = "once"
file.write(
' "%s"\n gamma %.6g\n premultiplied %s\n'
% (filepath, node.inputs["Gamma"].default_value, premul)
)
file.write(" %s\n" % once)
if node.map_type != "uv_mapping":
file.write(" map_type %s\n" % node.map_type)
file.write(" interpolate %s\n" % node.interpolate)
file.write(" }\n")
file.write(" %s\n" % transform)
file.write("#end\n")
for node in ntree.nodes:
pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayBumpMapNode" and node.outputs["Normal"].is_linked:
if node.image != "":
im = bpy.data.images[node.image]
if im.filepath and path.exists(bpy.path.abspath(im.filepath)):
transform = ""
for link in ntree.links:
if (
link.from_node.bl_idname == "PovrayTransformNode"
and link.to_node == node
):
pov_trans_name = (
string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ "_%s" % pov_mat_name
)
transform = "transform {%s}" % pov_trans_name
uv = ""
if node.map_type == "uv_mapping":
uv = "uv_mapping"
filepath = bpy.path.abspath(im.filepath)
file.write("#declare %s = normal {%s bump_map {\n" % (pov_node_name, uv))
once = ""
if node.once:
once = "once"
file.write(' "%s"\n' % filepath)
file.write(" %s\n" % once)
if node.map_type != "uv_mapping":
file.write(" map_type %s\n" % node.map_type)
bump_size = node.inputs["Normal"].default_value
if node.inputs["Normal"].is_linked:
pass
file.write(
" interpolate %s\n bump_size %.4g\n" % (node.interpolate, bump_size)
)
file.write(" }\n")
file.write(" %s\n" % transform)
file.write(" }\n")
declare_nodes.append(node.name)
for node in ntree.nodes:
pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayPigmentNode" and node.outputs["Pigment"].is_linked:
declare_nodes.append(node.name)
r, g, b = node.inputs["Color"].default_value[:]
f = node.inputs["Filter"].default_value
t = node.inputs["Transmit"].default_value
if node.inputs["Color"].is_linked:
pass
file.write(
"#declare %s = pigment{color srgbft <%.4g,%.4g,%.4g,%.4g,%.4g>}\n"
% (pov_node_name, r, g, b, f, t)
)
for node in ntree.nodes:
pov_node_name = string_strip_hyphen(bpy.path.clean_name(node.name)) + "_%s" % pov_mat_name
if node.bl_idname == "PovrayTextureNode" and node.outputs["Texture"].is_linked:
declare_nodes.append(node.name)
r, g, b = node.inputs["Pigment"].default_value[:]
pov_col_name = "color rgb <%.4g,%.4g,%.4g>" % (r, g, b)
if node.inputs["Pigment"].is_linked:
for link in ntree.links:
if link.to_node == node and link.to_socket.name == "Pigment":
pov_col_name = (
string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ "_%s" % pov_mat_name
)
file.write("#declare %s = texture{\n pigment{%s}\n" % (pov_node_name, pov_col_name))
if node.inputs["Normal"].is_linked:
for link in ntree.links:
if (
link.to_node == node
and link.to_socket.name == "Normal"
and link.from_node.name in declare_nodes
):
pov_nor_name = (
string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ "_%s" % pov_mat_name
)
file.write(" normal{%s}\n" % pov_nor_name)
if node.inputs["Finish"].is_linked:
for link in ntree.links:
if link.to_node == node and link.to_socket.name == "Finish":
pov_fin_name = (
string_strip_hyphen(bpy.path.clean_name(link.from_node.name))
+ "_%s" % pov_mat_name
)
file.write(" finish{%s}\n" % pov_fin_name)
file.write("}\n")
declare_nodes.append(node.name)
for i in range(0, len(ntree.nodes)):
for node in ntree.nodes:
if node.bl_idname in {"ShaderNodeGroup", "ShaderTextureMapNode"}:
for output in node.outputs:
if (
output.name == "Texture"
and output.is_linked
and (node.name not in declare_nodes)
):
declare = True
for link in ntree.links:
if link.to_node == node and link.to_socket.name not in {
"",
"Color ramp",
"Mapping",
"Transform",
"Modifier",
}:
if link.from_node.name not in declare_nodes:
declare = False
if declare:
pov_node_name = (
string_strip_hyphen(bpy.path.clean_name(node.name))
+ "_%s" % pov_mat_name
)
uv = ""
warp = ""
for link in ntree.links:
if (
link.to_node == node
and link.from_node.bl_idname == "PovrayMappingNode"
and link.from_node.warp_type != "NONE"
):
w_type = link.from_node.warp_type
if w_type == "uv_mapping":
uv = "uv_mapping"
else:
tor = ""
if w_type == "toroidal":
tor = (
"major_radius %.4g"
% link.from_node.warp_tor_major_radius
)
orient = link.from_node.warp_orientation
exp = link.from_node.warp_dist_exp
warp = "warp{%s orientation %s dist_exp %.4g %s}" % (
w_type,
orient,
exp,
tor,
)
if link.from_node.warp_type == "planar":
warp = "warp{%s %s %.4g}" % (w_type, orient, exp)
if link.from_node.warp_type == "cubic":
warp = "warp{%s}" % w_type
file.write("#declare %s = texture {%s\n" % (pov_node_name, uv))
pattern = node.inputs[0].default_value
advanced = ""
if node.inputs[0].is_linked:
for link in ntree.links:
if (
link.to_node == node
and link.from_node.bl_idname == "ShaderPatternNode"
):
# ------------ advanced ------------------------- #
lfn = link.from_node
pattern = lfn.pattern
if pattern == "agate":
advanced = "agate_turb %.4g" % lfn.agate_turb
if pattern == "crackle":
advanced = "form <%.4g,%.4g,%.4g>" % (
lfn.crackle_form_x,
lfn.crackle_form_y,
lfn.crackle_form_z,
)
advanced += " metric %.4g" % lfn.crackle_metric
if lfn.crackle_solid:
advanced += " solid"
if pattern in {"spiral1", "spiral2"}:
advanced = "%.4g" % lfn.spiral_arms
if pattern in {"tiling"}:
advanced = "%.4g" % lfn.tiling_number
if pattern in {"gradient"}:
advanced = "%s" % lfn.gradient_orient
if (
link.to_node == node
and link.from_node.bl_idname == "PovrayImagePatternNode"
):
pov_macro_name = (
string_strip_hyphen(
bpy.path.clean_name(link.from_node.name)
)
+ "_%s" % pov_mat_name
)
pattern = "%s()" % pov_macro_name
file.write(" %s %s %s\n" % (pattern, advanced, warp))
repeat = ""
for link in ntree.links:
if (
link.to_node == node
and link.from_node.bl_idname == "PovrayMultiplyNode"
):
if link.from_node.amount_x > 1:
repeat += "warp{repeat %.4g * x}" % link.from_node.amount_x
if link.from_node.amount_y > 1:
repeat += " warp{repeat %.4g * y}" % link.from_node.amount_y
if link.from_node.amount_z > 1:
repeat += " warp{repeat %.4g * z}" % link.from_node.amount_z
transform = ""
for link in ntree.links:
if (
link.to_node == node
and link.from_node.bl_idname == "PovrayTransformNode"
):
pov_trans_name = (
string_strip_hyphen(
bpy.path.clean_name(link.from_node.name)
)
+ "_%s" % pov_mat_name
)
transform = "transform {%s}" % pov_trans_name
x = 0
y = 0
z = 0
d = 0
e = 0
f = 0
g = 0
h = 0
modifier = False
for link in ntree.links:
if (
link.to_node == node
and link.from_node.bl_idname == "PovrayModifierNode"
):
modifier = True
if link.from_node.inputs["Turb X"].is_linked:
pass
else:
x = link.from_node.inputs["Turb X"].default_value
if link.from_node.inputs["Turb Y"].is_linked:
pass
else:
y = link.from_node.inputs["Turb Y"].default_value
if link.from_node.inputs["Turb Z"].is_linked:
pass
else:
z = link.from_node.inputs["Turb Z"].default_value
if link.from_node.inputs["Octaves"].is_linked:
pass
else:
d = link.from_node.inputs["Octaves"].default_value
if link.from_node.inputs["Lambda"].is_linked:
pass
else:
e = link.from_node.inputs["Lambda"].default_value
if link.from_node.inputs["Omega"].is_linked:
pass
else:
f = link.from_node.inputs["Omega"].default_value
if link.from_node.inputs["Frequency"].is_linked:
pass
else:
g = link.from_node.inputs["Frequency"].default_value
if link.from_node.inputs["Phase"].is_linked:
pass
else:
h = link.from_node.inputs["Phase"].default_value
turb = "turbulence <%.4g,%.4g,%.4g>" % (x, y, z)
octv = "octaves %s" % d
lmbd = "lambda %.4g" % e
omg = "omega %.4g" % f
freq = "frequency %.4g" % g
pha = "phase %.4g" % h
file.write("\n")
if pattern not in {
"checker",
"hexagon",
"square",
"triangular",
"brick",
}:
file.write(" texture_map {\n")
if node.inputs["Color ramp"].is_linked:
for link in ntree.links:
if (
link.to_node == node
and link.from_node.bl_idname == "ShaderNodeValToRGB"
):
els = link.from_node.color_ramp.elements
n = -1
for el in els:
n += 1
pov_in_mat_name = string_strip_hyphen(
bpy.path.clean_name(link.from_node.name)
) + "_%s_%s" % (n, pov_mat_name)
default = True
for ilink in ntree.links:
if (
ilink.to_node == node
and ilink.to_socket.name == str(n)
):
default = False
pov_in_mat_name = (
string_strip_hyphen(
bpy.path.clean_name(
ilink.from_node.name
)
)
+ "_%s" % pov_mat_name
)
if default:
r, g, b, a = el.color[:]
file.write(
" #declare %s = texture{"
"pigment{"
"color srgbt <%.4g,%.4g,%.4g,%.4g>}};\n"
% (pov_in_mat_name, r, g, b, 1 - a)
)
file.write(
" [%s %s]\n" % (el.position, pov_in_mat_name)
)
else:
els = [[0, 0, 0, 0], [1, 1, 1, 1]]
for t in range(0, 2):
pov_in_mat_name = string_strip_hyphen(
bpy.path.clean_name(link.from_node.name)
) + "_%s_%s" % (t, pov_mat_name)
default = True
for ilink in ntree.links:
if ilink.to_node == node and ilink.to_socket.name == str(t):
default = False
pov_in_mat_name = (
string_strip_hyphen(
bpy.path.clean_name(ilink.from_node.name)
)
+ "_%s" % pov_mat_name
)
if default:
r, g, b = els[t][1], els[t][2], els[t][3]
if pattern not in {
"checker",
"hexagon",
"square",
"triangular",
"brick",
}:
file.write(
" #declare %s = texture{pigment{color rgb <%.4g,%.4g,%.4g>}};\n"
% (pov_in_mat_name, r, g, b)
)
else:
file.write(
" texture{pigment{color rgb <%.4g,%.4g,%.4g>}}\n"
% (r, g, b)
)
if pattern not in {
"checker",
"hexagon",
"square",
"triangular",
"brick",
}:
file.write(" [%s %s]\n" % (els[t][0], pov_in_mat_name))
else:
if not default:
file.write(" texture{%s}\n" % pov_in_mat_name)
if pattern not in {
"checker",
"hexagon",
"square",
"triangular",
"brick",
}:
file.write("}\n")
if pattern == "brick":
file.write(
"brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"
% (
node.brick_size_x,
node.brick_size_y,
node.brick_size_z,
node.brick_mortar,
)
)
file.write(" %s %s" % (repeat, transform))
if modifier:
file.write(
" %s %s %s %s %s %s" % (turb, octv, lmbd, omg, freq, pha)
)
file.write("}\n")
declare_nodes.append(node.name)
for link in ntree.links:
if link.to_node.bl_idname == "PovrayOutputNode" and link.from_node.name in declare_nodes:
pov_mat_node_name = (
string_strip_hyphen(bpy.path.clean_name(link.from_node.name)) + "_%s" % pov_mat_name
)
file.write("#declare %s = %s\n" % (pov_mat_name, pov_mat_node_name))