-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcamera_map_checker.py
More file actions
189 lines (142 loc) · 5.38 KB
/
camera_map_checker.py
File metadata and controls
189 lines (142 loc) · 5.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
bl_info = {
"name": "Camera Map Checker",
"author": "Henri Hebeisen",
"version": (1, 0),
"blender": (2, 80, 0),
"location": "TBD",
"description": "Replace image texture with a checker to evaluate distortion",
"warning": "",
"wiki_url": "",
"category": "Material",
}
import bpy
from bpy.types import Operator
from bpy.props import BoolProperty
import mathutils
CHECKER_MAP = "checker_map"
CHECKER_NAME = "__checker_preview__"
def find_next_node(node):
return node.outputs[0].links[0].to_node
def find_image_node(material,uv_map_name):
nodes = bpy.data.materials[material].node_tree.nodes
uv_node = None
for node in nodes:
if node.type == 'UVMAP' and node.uv_map == uv_map_name:
uv_node = node
if uv_node is None:
return None
to_find = uv_node
while to_find.type != 'TEX_IMAGE':
to_find = find_next_node(to_find)
return to_find
def get_or_create_checker(size):
try :
image = bpy.data.images[CHECKER_MAP]
except :
image = bpy.data.images.new(CHECKER_MAP, width=size, height=size)
image.generated_type = 'UV_GRID'
return image
def create_checker_image_node(material,img_node):
node = bpy.data.materials[material].node_tree.nodes.new('ShaderNodeTexImage')
links = bpy.data.materials[material].node_tree.links
node.location = img_node.location + mathutils.Vector((0,-250))
node.name = img_node.name + CHECKER_NAME
#input reconnection
if len(img_node.inputs[0].links) > 0 :
links.new(img_node.inputs[0].links[0].from_socket,node.inputs[0])
#output reconnection
for output in img_node.outputs:
for link in output.links:
links.new(node.outputs[output.identifier],link.to_socket)
#image setup
image = get_or_create_checker(2048)
node.image = image
node.interpolation = img_node.interpolation
node.projection = img_node.projection
node.use_custom_color = True
node.color = (0.553794, 0.451944, 0.608)
def delete_checker_image_node(material):
checker_nodes = [node for node in bpy.data.materials[material].node_tree.nodes if node.name.endswith(CHECKER_NAME)]
links = bpy.data.materials[material].node_tree.links
for checker_node in checker_nodes:
img_node = bpy.data.materials[material].node_tree.nodes[checker_node.name[:-len(CHECKER_NAME)]]
#input reconnection
links.new(checker_node.inputs[0].links[0].from_socket,img_node.inputs[0])
#output reconnection
for output in checker_node.outputs:
for link in output.links:
links.new(img_node.outputs[output.identifier],link.to_socket)
#we delete the checker node
bpy.data.materials[material].node_tree.nodes.remove(checker_node)
def get_all_UV_MAP_from_modifier(object):
result = []
for modifier in object.modifiers:
if modifier.type !='UV_PROJECT':
continue
if modifier.uv_layer:
result.append(modifier.uv_layer)
return result
def get_image_nodes(mat,uv_maps):
nodes = []
for uv_map in uv_maps:
nodes.append(find_image_node(mat.name,uv_map))
return nodes
def set_checker(self,context):
obj = context.active_object
UV_maps = get_all_UV_MAP_from_modifier(obj)
for mat in obj.data.materials:
nodes = get_image_nodes(mat,UV_maps)
for img_node in nodes:
create_checker_image_node(mat.name,img_node)
bpy.context.scene["IsCheckerEnabled"] = True
def remove_checker(self,context):
obj = context.active_object
for mat in obj.data.materials:
delete_checker_image_node(mat.name)
bpy.context.scene["IsCheckerEnabled"] = False
class OBJECT_OT_set_checker(Operator):
"""Set checker"""
bl_idname = "material.set_checker"
bl_label = "Set Checker"
bl_options = {'REGISTER', 'UNDO'}
IsCheckerEnabled: bpy.props.BoolProperty(name="Enabled", default=False)
def execute(self, context):
if not self.IsCheckerEnabled :
set_checker(self, context)
self.IsCheckerEnabled = True
else :
remove_checker(self,context)
self.IsCheckerEnabled = False
return {'FINISHED'}
# Registration
class SetCheckerPanel(bpy.types.Panel):
"""Creates a Panel in the scene context of the properties editor"""
bl_label = "Camera Map Tool"
bl_idname = "SCENE_PT_set_checker"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "material"
def draw(self, context):
layout = self.layout
scene = context.scene
# Create a simple row.
row = layout.row()
row.operator("material.set_checker",text="Set checker",
icon='PLUGIN')
# This allows you to right click on a button and link to the manual
def set_checker_manual_map():
url_manual_prefix = "https://docs.blender.org/manual/en/dev/"
url_manual_mapping = (
("bpy.ops.material.set_checker", "editors/properties/object"),
)
return url_manual_prefix, url_manual_mapping
def register():
bpy.utils.register_class(OBJECT_OT_set_checker)
bpy.utils.register_manual_map(set_checker_manual_map)
bpy.utils.register_class(SetCheckerPanel)
def unregister():
bpy.utils.unregister_class(OBJECT_OT_set_checker)
bpy.utils.unregister_manual_map(set_checker_manual_map)
bpy.utils.unregister_class(SetCheckerPanel)
if __name__ == "__main__":
register()