Newer
Older
# Copyright 2015 Théo Friberg under GNU GPL 3
if "bpy" in locals():
import importlib
importlib.reload(JSONOps)
else:
from . import JSONOps
import bpy
import os
import glob
class AutomatOperatorFromTexture(bpy.types.Operator):
"""This operator generates automatic materials from textures in Cycles."""
# Metadata of the operator
bl_idname = "com.new_automat"
bl_label = "Automatic Material from Image"
bl_options = {"UNDO"}
# Variables used for storing the filepath given by blender's file manager
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filename: bpy.props.StringProperty()
directory: bpy.props.StringProperty(subtype="FILE_PATH")
make_seamless: bpy.props.BoolProperty(name="Make Seamless", description="Make tileable (removes visible borders of the image).")
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
def execute(self, context):
"""This is the main runnable method of the operator.
This creates all the node setup."""
# Create the material
mat = bpy.data.materials.new(self.filename)
mat.use_nodes = True
nodes = mat.node_tree.nodes
# Empty whatever nodes we allready had.
for node in nodes.keys():
nodes.remove(nodes[node])
nodes_dict = {}
# Create the main part of the material
nodes_dict = JSONOps.inflateFile(mat, os.path.dirname(
os.path.realpath(__file__))+os.sep+
"automatic_material.json")
# We load the images
image_data = bpy.data.images.load(self.filepath)
nodes_dict["Color Image"].image = image_data
# We check if the texture must be made seamless
if self.make_seamless:
seamless_vector = JSONOps.inflateFile(mat, os.path.dirname(os.path.realpath(__file__))+os.sep+"seamless_vector.json", -3000, 0)
links = mat.node_tree.links
links.new(seamless_vector["Pick Vector"].outputs["Color"], nodes_dict["Color Image"].inputs["Vector"])
# Below we check potential maps
modified_fname = self.filename.split(".")
# Check if we are dealing with maps generated with CrazyBump.
# If so is the case, the color map is by default suffixed with _COLOR
known_scheme = False
if modified_fname[0][-6:] == "_COLOR":
# We are dealing with CrazyBump and we remove the suffix
modified_fname[0] = modified_fname[0][:-6]
known_scheme = True
other_files = []
folder = os.path.split(self.filepath)[0]+os.path.sep+"*"
pattern = folder + ".".join(modified_fname[:-1])+"*."+modified_fname[-1]
other_files = glob.glob(pattern)
# We check if we can find a Specularity Map
specmap = ""
for file in other_files:
if "spec" in os.path.split(file)[-1].lower():
specmap = file
break
if len(specmap) > 0:
spec_map = nodes.new("ShaderNodeTexImage")
spec_map.location = [nodes_dict["Adjust reflectivity"].location[0],
nodes_dict["Adjust reflectivity"].location[1]+50]
spec_map.label = "Specularity Map"
nodes.remove(nodes_dict["Adjust reflectivity"])
spec_map.image = bpy.data.images.load(specmap)
links = mat.node_tree.links
links.new(spec_map.outputs["Color"],
nodes_dict["Mix Shaders"].inputs[0])
if self.make_seamless:
links.new(seamless_vector["Pick Vector"].outputs["Color"], spec_map.inputs["Vector"])
# We check if we can find a Normal Map
normalmap = ""
for file in other_files:
if "normal" in os.path.split(file)[-1].lower() or ".".join(os.path.split(file)[1].split(".") [:-1])[-4:] == "_NRM":
normalmap = file
break
if len(normalmap) > 0 and ((not "normal" in self.filename.lower()) or known_scheme):
normal_map = nodes.new("ShaderNodeTexImage")
normal_map.location = [nodes_dict["Color Image"].location[0],
nodes_dict["Color Image"].location[1]-240]
normal_map.label = "Normal Map"
normal_map.image = bpy.data.images.load(normalmap)
links = mat.node_tree.links
normal = nodes.new("ShaderNodeNormalMap")
normal.location = [nodes_dict["Convert to Bump Map"].location[0],
nodes_dict["Convert to Bump Map"].location[1]]
nodes.remove(nodes_dict["Convert to Bump Map"])
links.new(normal_map.outputs["Color"],
normal.inputs[1])
links.new(normal.outputs["Normal"],
nodes_dict["Diffuse Component"].inputs[2])
links.new(normal.outputs["Normal"],
nodes_dict["Glossy Component"].inputs[2])
if self.make_seamless:
links.new(seamless_vector["Pick Vector"].outputs["Color"], normal_map.inputs["Vector"])
# We check if we can find a Bump Map
bumpmap = ""
for file in other_files:
if "bump" in os.path.split(file.lower())[-1]:
bumpmap = file
break
if len(bumpmap) > 0 and not "bump" in self.filename.lower() and not len(normalmap) > 0:
bump_map = nodes.new("ShaderNodeTexImage")
bump_map.location = [nodes_dict["Color Image"].location[0],
nodes_dict["Color Image"].location[1]-240]
bump_map.label = "Bump Map"
bump_map.image = bpy.data.images.load(bumpmap)
links = mat.node_tree.links
links.new(bump_map.outputs["Color"], nodes_dict["Convert to Bump Map"].inputs[2])
if self.make_seamless:
links.new(seamless_vector["Pick Vector"].outputs["Color"], bump_map.inputs["Vector"])
# Try to add the material to the selected object
try:
bpy.context.object.data.materials.append(mat)
except AttributeError:
# If there is no object with materials selected,
# don't add the material to anythinng.
pass
# Tell that all went well
return {"FINISHED"}
def invoke(self, context, event):
"""This method opens the file browser. After that, the
execute(...) method gets ran, creating the node setup.
It also checks that the render engine is Cycles. """
if bpy.context.scene.render.engine == 'CYCLES':
self.filename = ""
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
else:
self.report({'ERROR'}, "Can't generate Cycles material with Blender"
"internal as active renderer.")
return {"FINISHED"}