1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
22 Bake UV-Texture to Vertex Colors Addon
24 Contact: p_boelens@msn.com
25 Information: https://developer.blender.org/T28211
27 Contributor(s): Patrick Boelens, CoDEmanX.
33 "name": "Bake UV-Texture to Vertex Colors",
34 "description": "Bakes the colors of the active UV Texture "
35 "to a Vertex Color layer.",
36 "author": "Patrick Boelens, CoDEmanX",
38 "blender": (2, 63, 0),
39 "location": "3D View > Vertex Paint > Toolshelf > Bake",
40 "warning": "Requires image texture, generated textures aren't supported.",
41 "wiki_url": "http://wiki.blender.org/index.php?title=Extensions:2.6/Py/"
42 "Scripts/UV/Bake_Texture_to_Vertex_Colors",
47 from bpy
.props
import BoolProperty
, EnumProperty
, FloatVectorProperty
49 from colorsys
import rgb_to_hsv
, hsv_to_rgb
51 class UV_OT_bake_texture_to_vcols(bpy
.types
.Operator
):
52 bl_idname
= "uv.bake_texture_to_vcols"
53 bl_label
= "Bake UV-Texture to Vertex Colors"
54 bl_description
= "Bake active UV-Texture to new Vertex Color layer "\
55 "(requires image texture)"
56 bl_options
= {'REGISTER', 'UNDO'}
58 replace_active_layer
= BoolProperty(
60 description
="Overwrite active Vertex Color layer",
64 ("CLIP", "Clip", "Don't affect vertices who's UV-coordinates are out of bounds."),
65 ("REPEAT", "Repeat", "Tile the image so that each vertex is accounted for."),
66 ("EXTEND", "Extend", "Extends the edges of the image to the UV-coordinates.")]
68 mappingMode
= EnumProperty(
72 description
="The mode to use for baking vertices who's UV-coordinates are out of bounds")
74 blendingModes
= [("MIX", "Mix", ""),
76 ("SUBTRACT", "Subtract", ""),
77 ("MULTIPLY", "Multiply", ""),
78 ("SCREEN", "Screen", ""),
79 ("OVERLAY", "Overlay", ""),
80 ("DIFFERENCE", "Difference", ""),
81 ("DIVIDE", "Divide", ""),
82 ("DARKEN", "Darken", ""),
83 ("LIGHTEN", "Lighten", ""),
85 ("SATURATION", "Saturation", ""),
86 ("VALUE", "Value", ""),
87 ("COLOR", "Color", ""),
88 ("SOFT_LIGHT", "Soft Light", ""),
89 ("LINEAR_LIGHT", "Linear Light", "")
92 blendingMode
= EnumProperty(
96 description
="The blending mode to use when baking")
98 mirror_x
= BoolProperty(name
="Mirror X", description
="Mirror the image on the X-axis")
99 mirror_y
= BoolProperty(name
="Mirror Y", description
="Mirror the image on the Y-axis")
102 def poll(self
, context
):
103 return (context
.object and
104 context
.object.type == 'MESH' and
105 context
.mode
!= 'EDIT_MESH' and
106 context
.object.data
.uv_layers
.active
and
107 context
.object.data
.uv_textures
.active
)
109 def execute(self
, context
):
110 obdata
= context
.object.data
112 if self
.replace_active_layer
and obdata
.vertex_colors
.active
:
113 vertex_colors
= obdata
.vertex_colors
.active
115 vertex_colors
= obdata
.vertex_colors
.new(name
="Baked UV texture")
117 if not vertex_colors
:
119 # Can't add more than 17 VCol layers
120 self
.report({'ERROR'},
121 "Couldn't add another Vertex Color layer,\n"
122 "Please remove an existing layer or replace active.")
126 obdata
.vertex_colors
.active
= vertex_colors
129 for uv_tex
in obdata
.uv_textures
.active
.data
:
131 uv_tex
.image
.name
not in uv_images
and
132 uv_tex
.image
.pixels
):
134 uv_images
[uv_tex
.image
.name
] = (
135 uv_tex
.image
.size
[0],
136 uv_tex
.image
.size
[1],
137 uv_tex
.image
.pixels
[:]
138 # Accessing pixels directly is far too slow.
139 # Copied to new array for massive performance-gain.
142 for p
in obdata
.polygons
:
143 img
= obdata
.uv_textures
.active
.data
[p
.index
].image
147 image_size_x
, image_size_y
, uv_pixels
= uv_images
[img
.name
]
149 for loop
in p
.loop_indices
:
151 co
= obdata
.uv_layers
.active
.data
[loop
].uv
152 x_co
= round(co
[0] * (image_size_x
- 1))
153 y_co
= round(co
[1] * (image_size_y
- 1))
155 if x_co
< 0 or x_co
>= image_size_x
or y_co
< 0 or y_co
>= image_size_y
:
156 if self
.mappingMode
== 'CLIP':
159 elif self
.mappingMode
== 'REPEAT':
163 elif self
.mappingMode
== 'EXTEND':
164 if x_co
> image_size_x
- 1:
165 x_co
= image_size_x
- 1
168 if y_co
> image_size_y
- 1:
169 y_co
= image_size_y
- 1
174 x_co
= image_size_x
-1 - x_co
177 y_co
= image_size_y
-1 - y_co
179 col_out
= vertex_colors
.data
[loop
].color
181 pixelNumber
= (image_size_x
* y_co
) + x_co
182 r
= uv_pixels
[pixelNumber
*4]
183 g
= uv_pixels
[pixelNumber
*4 + 1]
184 b
= uv_pixels
[pixelNumber
*4 + 2]
185 a
= uv_pixels
[pixelNumber
*4 + 3]
187 col_in
= r
, g
, b
# texture-color
188 col_result
= [r
,g
,b
] # existing / 'base' color
190 if self
.blendingMode
== 'MIX':
193 elif self
.blendingMode
== 'ADD':
194 col_result
[0] = col_in
[0] + col_out
[0]
195 col_result
[1] = col_in
[1] + col_out
[1]
196 col_result
[2] = col_in
[2] + col_out
[2]
198 elif self
.blendingMode
== 'SUBTRACT':
199 col_result
[0] = col_in
[0] - col_out
[0]
200 col_result
[1] = col_in
[1] - col_out
[1]
201 col_result
[2] = col_in
[2] - col_out
[2]
203 elif self
.blendingMode
== 'MULTIPLY':
204 col_result
[0] = col_in
[0] * col_out
[0]
205 col_result
[1] = col_in
[1] * col_out
[1]
206 col_result
[2] = col_in
[2] * col_out
[2]
208 elif self
.blendingMode
== 'SCREEN':
209 col_result
[0] = 1 - (1.0 - col_in
[0]) * (1.0 - col_out
[0])
210 col_result
[1] = 1 - (1.0 - col_in
[1]) * (1.0 - col_out
[1])
211 col_result
[2] = 1 - (1.0 - col_in
[2]) * (1.0 - col_out
[2])
213 elif self
.blendingMode
== 'OVERLAY':
215 col_result
[0] = col_out
[0] * (2.0 * col_in
[0])
217 col_result
[0] = 1.0 - (2.0 * (1.0 - col_in
[0])) * (1.0 - col_out
[0])
219 col_result
[1] = col_out
[1] * (2.0 * col_in
[1])
221 col_result
[1] = 1.0 - (2.0 * (1.0 - col_in
[1])) * (1.0 - col_out
[1])
223 col_result
[2] = col_out
[2] * (2.0 * col_in
[2])
225 col_result
[2] = 1.0 - (2.0 * (1.0 - col_in
[2])) * (1.0 - col_out
[2])
227 elif self
.blendingMode
== 'DIFFERENCE':
228 col_result
[0] = fabs(col_in
[0] - col_out
[0])
229 col_result
[1] = fabs(col_in
[1] - col_out
[1])
230 col_result
[2] = fabs(col_in
[2] - col_out
[2])
232 elif self
.blendingMode
== 'DIVIDE':
233 if(col_in
[0] != 0.0):
234 col_result
[0] = col_out
[0] / col_in
[0]
235 if(col_in
[1] != 0.0):
236 col_result
[0] = col_out
[1] / col_in
[1]
237 if(col_in
[2] != 0.0):
238 col_result
[2] = col_out
[2] / col_in
[2]
240 elif self
.blendingMode
== 'DARKEN':
241 if col_in
[0] < col_out
[0]:
242 col_result
[0] = col_in
[0]
244 col_result
[0] = col_out
[0]
245 if col_in
[1] < col_out
[1]:
246 col_result
[1] = col_in
[1]
248 col_result
[1] = col_out
[1]
249 if col_in
[2] < col_out
[2]:
250 col_result
[2] = col_in
[2]
252 col_result
[2] = col_out
[2]
255 elif self
.blendingMode
== 'LIGHTEN':
256 if col_in
[0] > col_out
[0]:
257 col_result
[0] = col_in
[0]
259 col_result
[0] = col_out
[0]
260 if col_in
[1] > col_out
[1]:
261 col_result
[1] = col_in
[1]
263 col_result
[1] = col_out
[1]
264 if col_in
[2] > col_out
[2]:
265 col_result
[2] = col_in
[2]
267 col_result
[2] = col_out
[2]
269 elif self
.blendingMode
== 'HUE':
270 hsv_in
= rgb_to_hsv(col_in
[0], col_in
[1], col_in
[2])
271 hsv_out
= rgb_to_hsv(col_out
[0], col_out
[1], col_out
[2])
273 col_result
= hsv_to_rgb(hue
, hsv_out
[1], hsv_out
[2])
275 elif self
.blendingMode
== 'SATURATION':
276 hsv_in
= rgb_to_hsv(col_in
[0], col_in
[1], col_in
[2])
277 hsv_out
= rgb_to_hsv(col_out
[0], col_out
[1], col_out
[2])
279 col_result
= hsv_to_rgb(hsv_out
[0], sat
, hsv_out
[2])
281 elif self
.blendingMode
== 'VALUE':
282 hsv_in
= rgb_to_hsv(col_in
[0], col_in
[1], col_in
[2])
283 hsv_out
= rgb_to_hsv(col_out
[0], col_out
[1], col_out
[2])
285 col_result
= hsv_to_rgb(hsv_out
[0], hsv_out
[1], val
)
287 elif self
.blendingMode
== 'COLOR':
288 hsv_in
= rgb_to_hsv(col_in
[0], col_in
[1], col_in
[2])
289 hsv_out
= rgb_to_hsv(col_out
[0], col_out
[1], col_out
[2])
292 col_result
= hsv_to_rgb(hue
, sat
, hsv_out
[2])
294 elif self
.blendingMode
== 'SOFT_LIGHT':
295 scr
= 1 - (1.0 - col_in
[0]) * (1.0 - col_out
[0])
296 scg
= 1 - (1.0 - col_in
[1]) * (1.0 - col_out
[1])
297 scb
= 1 - (1.0 - col_in
[2]) * (1.0 - col_out
[2])
299 col_result
[0] = (1.0 - col_out
[0]) * (col_in
[0] * col_out
[0]) + (col_out
[0] * scr
)
300 col_result
[1] = (1.0 - col_out
[1]) * (col_in
[1] * col_out
[1]) + (col_out
[1] * scg
)
301 col_result
[2] = (1.0 - col_out
[2]) * (col_in
[2] * col_out
[2]) + (col_out
[2] * scb
)
304 elif self
.blendingMode
== 'LINEAR_LIGHT':
306 col_result
[0] = col_out
[0] + 2.0 * (col_in
[0] - 0.5)
308 col_result
[0] = col_out
[0] + 2.0 * (col_in
[0] - 1.0)
310 col_result
[1] = col_out
[1] + 2.0 * (col_in
[1] - 0.5)
312 col_result
[1] = col_out
[1] + 2.0 * (col_in
[1] - 1.0)
314 col_result
[2] = col_out
[2] + 2.0 * (col_in
[2] - 0.5)
316 col_result
[2] = col_out
[2] + 2.0 * (col_in
[2] - 1.0)
320 alpha_color
= context
.scene
.uv_bake_alpha_color
321 col_result
= (col_result
[0] * a
+ alpha_color
[0] * a_inverted
,
322 col_result
[1] * a
+ alpha_color
[1] * a_inverted
,
323 col_result
[2] * a
+ alpha_color
[2] * a_inverted
)
325 vertex_colors
.data
[loop
].color
= col_result
329 class VIEW3D_PT_tools_uv_bake_texture_to_vcols(bpy
.types
.Panel
):
331 bl_space_type
= "VIEW_3D"
332 bl_region_type
= "TOOLS"
333 bl_options
= {'DEFAULT_CLOSED'}
336 def poll(self
, context
):
337 return(context
.mode
== 'PAINT_VERTEX')
339 def draw(self
, context
):
341 col
= layout
.column()
342 col
.prop(context
.scene
, "uv_bake_alpha_color")
344 col
.operator("uv.bake_texture_to_vcols", text
="UV Texture to VCols")
347 bpy
.utils
.register_module(__name__
)
348 bpy
.types
.Scene
.uv_bake_alpha_color
= FloatVectorProperty(
350 description
="Color to be used for transparency",
356 bpy
.utils
.unregister_module(__name__
)
357 del bpy
.types
.Scene
.uv_bake_alpha_color
359 if __name__
== "__main__":