@ -32,10 +32,12 @@ modes={
if hasattr ( bpy . types , " ShaderNodeBevel " ) :
# Has newer bevel shader (2.7 nightly build series)
modes [ ' bevel_mask ' ] = ub . BakeMode ( ' bake_bevel_mask ' , type = ' EMIT ' , color = ( 0 , 0 , 0 , 1 ) , params = [ " bake_bevel_samples " , " bake_bevel_size " ] )
modes [ ' normal_tangent_bevel ' ] = ub . BakeMode ( ' bake_bevel_normal ' , type = ' NORMAL ' , color = ( 0.5 , 0.5 , 1 , 1 ) , params = [ " bake_bevel_samples " , " bake_bevel_size " ] )
modes [ ' normal_object_bevel ' ] = ub . BakeMode ( ' bake_bevel_normal ' , type = ' NORMAL ' , color = ( 0.5 , 0.5 , 1 , 1 ) , normal_space = ' OBJECT ' , params = [ " bake_bevel_samples " , " bake_bevel_size " ] )
modes [ ' bevel_mask ' ] = ub . BakeMode ( ' bake_bevel_mask ' , type = ' EMIT ' , color = (
0 , 0 , 0 , 1 ) , params = [ " bake_bevel_samples " , " bake_bevel_size " ] )
modes [ ' normal_tangent_bevel ' ] = ub . BakeMode ( ' bake_bevel_normal ' , type = ' NORMAL ' , color = (
0.5 , 0.5 , 1 , 1 ) , params = [ " bake_bevel_samples " , " bake_bevel_size " ] )
modes [ ' normal_object_bevel ' ] = ub . BakeMode ( ' bake_bevel_normal ' , type = ' NORMAL ' , color = (
0.5 , 0.5 , 1 , 1 ) , normal_space = ' OBJECT ' , params = [ " bake_bevel_samples " , " bake_bevel_size " ] )
class op ( bpy . types . Operator ) :
@ -53,7 +55,8 @@ class op(bpy.types.Operator):
bake_mode = utilities_ui . get_bake_mode ( )
if bake_mode not in modes :
self . report ( { ' ERROR_INVALID_INPUT ' } , " Uknown mode ' {} ' only available: ' {} ' " . format ( bake_mode , " , " . join ( modes . keys ( ) ) ) )
self . report ( { ' ERROR_INVALID_INPUT ' } , " Uknown mode ' {} ' only available: ' {} ' " . format (
bake_mode , " , " . join ( modes . keys ( ) ) ) )
return
# Store Selection
@ -68,7 +71,8 @@ class op(bpy.types.Operator):
size = bpy . context . scene . texToolsSettings . size ,
bake_single = bpy . context . scene . texToolsSettings . bake_force_single ,
sampling_scale = int ( bpy . context . scene . texToolsSettings . bake_sampling ) ,
sampling_scale = int (
bpy . context . scene . texToolsSettings . bake_sampling ) ,
samples = bpy . context . scene . texToolsSettings . bake_samples ,
ray_distance = bpy . context . scene . texToolsSettings . bake_ray_distance
)
@ -84,12 +88,12 @@ class op(bpy.types.Operator):
return { ' FINISHED ' }
def bake ( self , mode , size , bake_single , sampling_scale , samples , ray_distance ) :
print ( " Bake ' {} ' " . format ( mode ) )
bpy . context . scene . render . engine = modes [ mode ] . engine #Switch render engine
# Switch render engine
bpy . context . scene . render . engine = modes [ mode ] . engine
# Disable edit mode
if bpy . context . view_layer . objects . active != None and bpy . context . object . mode != ' OBJECT ' :
@ -109,23 +113,27 @@ def bake(self, mode, size, bake_single, sampling_scale, samples, ray_distance):
# Get image name
name_texture = " {} _ {} " . format ( set . name , mode )
if bake_single :
name_texture = " {} _ {} " . format ( sets [ 0 ] . name , mode ) # In Single mode bake into same texture
# In Single mode bake into same texture
name_texture = " {} _ {} " . format ( sets [ 0 ] . name , mode )
path = bpy . path . abspath ( " // {} .tga " . format ( name_texture ) )
# Requires 1+ low poly objects
if len ( set . objects_low ) == 0 :
self . report ( { ' ERROR_INVALID_INPUT ' } , " No low poly object as part of the ' {} ' set " . format ( set . name ) )
self . report ( { ' ERROR_INVALID_INPUT ' } ,
" No low poly object as part of the ' {} ' set " . format ( set . name ) )
return
# Check for UV maps
for obj in set . objects_low :
if not obj . data . uv_layers or len ( obj . data . uv_layers ) == 0 :
self . report ( { ' ERROR_INVALID_INPUT ' } , " No UV map available for ' {} ' " . format ( obj . name ) )
self . report ( { ' ERROR_INVALID_INPUT ' } ,
" No UV map available for ' {} ' " . format ( obj . name ) )
return
# Check for cage inconsistencies
if len ( set . objects_cage ) > 0 and ( len ( set . objects_low ) != len ( set . objects_cage ) ) :
self . report ( { ' ERROR_INVALID_INPUT ' } , " {} x cage objects do not match {} x low poly objects for ' {} ' " . format ( len ( set . objects_cage ) , len ( set . objects_low ) , obj . name ) )
self . report ( { ' ERROR_INVALID_INPUT ' } , " {} x cage objects do not match {} x low poly objects for ' {} ' " . format (
len ( set . objects_cage ) , len ( set . objects_low ) , obj . name ) )
return
# Get Materials
@ -136,7 +144,6 @@ def bake(self, mode, size, bake_single, sampling_scale, samples, ray_distance):
else :
material_empty = bpy . data . materials . new ( name = " TT_bake_node " )
# Assign Materials to Objects
if ( len ( set . objects_high ) + len ( set . objects_float ) ) == 0 :
# Low poly bake: Assign material to lowpoly
@ -153,15 +160,14 @@ def bake(self, mode, size, bake_single, sampling_scale, samples, ray_distance):
assign_vertex_color ( mode , obj )
assign_material ( mode , obj , material_loaded )
# Setup Image
is_clear = ( not bake_single ) or ( bake_single and s == 0 )
image = setup_image ( mode , name_texture , render_width , render_height , path , is_clear )
image = setup_image ( mode , name_texture , render_width ,
render_height , path , is_clear )
# Assign bake node to Material
setup_image_bake_node ( set . objects_low [ 0 ] , image )
print ( " Bake ' {} ' = {} " . format ( set . name , path ) )
# Hide all cage objects i nrender
@ -171,7 +177,8 @@ def bake(self, mode, size, bake_single, sampling_scale, samples, ray_distance):
# Bake each low poly object in this set
for i in range ( len ( set . objects_low ) ) :
obj_low = set . objects_low [ i ]
obj_cage = None if i > = len ( set . objects_cage ) else set . objects_cage [ i ]
obj_cage = None if i > = len (
set . objects_cage ) else set . objects_cage [ i ]
# Disable hide render
obj_low . hide_render = False
@ -190,7 +197,6 @@ def bake(self, mode, size, bake_single, sampling_scale, samples, ray_distance):
area . spaces [ 0 ] . image = image
# bpy.data.screens['UV Editing'].areas[1].spaces[0].image = image
bpy . ops . object . mode_set ( mode = ' OBJECT ' )
for obj_high in ( set . objects_high ) :
@ -231,7 +237,6 @@ def bake(self, mode, size, bake_single, sampling_scale, samples, ray_distance):
for obj_cage in set . objects_cage :
obj_cage . hide_render = False
# Downsample image?
if not bake_single or ( bake_single and s == len ( sets ) - 1 ) :
# When baking single, only downsample on last bake
@ -240,7 +245,8 @@ def bake(self, mode, size, bake_single, sampling_scale, samples, ray_distance):
# Apply composite nodes on final image result
if modes [ mode ] . composite :
apply_composite ( image , modes [ mode ] . composite , bpy . context . scene . texToolsSettings . bake_curvature_size )
apply_composite (
image , modes [ mode ] . composite , bpy . context . scene . texToolsSettings . bake_curvature_size )
# image.save()
@ -248,8 +254,6 @@ def bake(self, mode, size, bake_single, sampling_scale, samples, ray_distance):
ub . restore_materials ( )
def apply_composite ( image , scene_name , size ) :
previous_scene = bpy . context . window . scene
@ -258,8 +262,10 @@ def apply_composite(image, scene_name, size):
if scene_name in bpy . data . scenes :
scene = bpy . data . scenes [ scene_name ]
else :
path = os . path . join ( os . path . dirname ( __file__ ) , " resources/compositing.blend " ) + " \\ Scene \\ "
bpy . ops . wm . append ( filename = scene_name , directory = path , link = False , autoselect = False )
path = os . path . join ( os . path . dirname ( __file__ ) ,
" resources/compositing.blend " ) + " \\ Scene \\ "
bpy . ops . wm . append ( filename = scene_name , directory = path ,
link = False , autoselect = False )
scene = bpy . data . scenes [ scene_name ]
if scene :
@ -272,12 +278,12 @@ def apply_composite(image, scene_name, size):
if " Offset " in scene . node_tree . nodes :
scene . node_tree . nodes [ " Offset " ] . outputs [ 0 ] . default_value = size
print ( " Assign offset: {} " . format ( scene . node_tree . nodes [ " Offset " ] . outputs [ 0 ] . default_value ) )
print ( " Assign offset: {} " . format (
scene . node_tree . nodes [ " Offset " ] . outputs [ 0 ] . default_value ) )
# Render image
bpy . ops . render . render ( use_viewport = False )
# Get last images of viewer node and render result
image_viewer_node = get_last_item ( " Viewer Node " , bpy . data . images )
image_render_result = get_last_item ( " Render Result " , bpy . data . images )
@ -298,7 +304,6 @@ def apply_composite(image, scene_name, size):
bpy . data . scenes . remove ( scene )
def get_last_item ( key_name , collection ) :
# bpy.data.images
# Get last image of a series, e.g. .001, .002, 003
@ -315,8 +320,6 @@ def get_last_item(key_name, collection):
return None
def setup_image ( mode , name , width , height , path , is_clear ) :
image = None
@ -332,7 +335,6 @@ def setup_image(mode, name, width, height, path, is_clear):
# if bpy.data.images[name].has_data == False:
# Previous image does not have data, remove first
# print("Image pointer exists but no data "+name)
# image = bpy.data.images[name]
@ -343,13 +345,13 @@ def setup_image(mode, name, width, height, path, is_clear):
if name not in bpy . data . images :
# Create new image with 32 bit float
is_float_32 = bpy . context . preferences . addons [ " textools " ] . preferences . bake_32bit_float == ' 32 '
image = bpy . data . images . new ( name , width = width , height = height , float_buffer = is_float_32 )
image = bpy . data . images . new (
name , width = width , height = height , float_buffer = is_float_32 )
if " _normal_ " in image . name :
image . colorspace_settings . name = ' Non-Color '
else :
image . colorspace_settings . name = ' sRGB '
else :
# Reuse existing Image
image = bpy . data . images [ name ]
@ -364,7 +366,6 @@ def setup_image(mode, name, width, height, path, is_clear):
image . generated_color = modes [ mode ] . color
image . generated_type = ' BLANK '
image . file_format = ' TARGA '
# TODO: Verify that the path exists
@ -373,7 +374,6 @@ def setup_image(mode, name, width, height, path, is_clear):
return image
def setup_image_bake_node ( obj , image ) :
if len ( obj . data . materials ) < = 0 :
@ -397,13 +397,11 @@ def setup_image_bake_node(obj, image):
tree . nodes . active = node
def assign_vertex_color ( mode , obj ) :
if modes [ mode ] . setVColor :
modes [ mode ] . setVColor ( obj )
def assign_material ( mode , obj , material_bake = None , material_empty = None ) :
ub . store_materials ( obj )
@ -412,31 +410,32 @@ def assign_material(mode, obj, material_bake=None, material_empty=None):
# Select All faces
bpy . ops . object . mode_set ( mode = ' EDIT ' )
bm = bmesh . from_edit_mesh ( bpy . context . active_object . data ) ;
bm = bmesh . from_edit_mesh ( bpy . context . active_object . data )
faces = [ face for face in bm . faces if face . select ]
bpy . ops . mesh . select_all ( action = ' SELECT ' )
if material_bake :
# Setup properties of bake materials
if mode == ' wireframe ' :
if " Value " in material_bake . node_tree . nodes :
material_bake . node_tree . nodes [ " Value " ] . outputs [ 0 ] . default_value = bpy . context . scene . texToolsSettings . bake_wireframe_size
material_bake . node_tree . nodes [ " Value " ] . outputs [
0 ] . default_value = bpy . context . scene . texToolsSettings . bake_wireframe_size
if mode == ' bevel_mask ' :
if " Bevel " in material_bake . node_tree . nodes :
material_bake . node_tree . nodes [ " Bevel " ] . inputs [ 0 ] . default_value = bpy . context . scene . texToolsSettings . bake_bevel_size
material_bake . node_tree . nodes [ " Bevel " ] . inputs [
0 ] . default_value = bpy . context . scene . texToolsSettings . bake_bevel_size
material_bake . node_tree . nodes [ " Bevel " ] . samples = bpy . context . scene . texToolsSettings . bake_bevel_samples
if mode == ' normal_tangent_bevel ' :
if " Bevel " in material_bake . node_tree . nodes :
material_bake . node_tree . nodes [ " Bevel " ] . inputs [ 0 ] . default_value = bpy . context . scene . texToolsSettings . bake_bevel_size
material_bake . node_tree . nodes [ " Bevel " ] . inputs [
0 ] . default_value = bpy . context . scene . texToolsSettings . bake_bevel_size
material_bake . node_tree . nodes [ " Bevel " ] . samples = bpy . context . scene . texToolsSettings . bake_bevel_samples
if mode == ' normal_object_bevel ' :
if " Bevel " in material_bake . node_tree . nodes :
material_bake . node_tree . nodes [ " Bevel " ] . inputs [ 0 ] . default_value = bpy . context . scene . texToolsSettings . bake_bevel_size
material_bake . node_tree . nodes [ " Bevel " ] . inputs [
0 ] . default_value = bpy . context . scene . texToolsSettings . bake_bevel_size
material_bake . node_tree . nodes [ " Bevel " ] . samples = bpy . context . scene . texToolsSettings . bake_bevel_samples
# Don't apply in diffuse mode
if mode != ' diffuse ' :
if material_bake :
@ -467,38 +466,31 @@ def assign_material(mode, obj, material_bake=None, material_empty=None):
bpy . ops . object . mode_set ( mode = ' OBJECT ' )
def get_material ( mode ) :
if modes [ mode ] . material == " " :
return None # No material setup requires
# Find or load material
name = modes [ mode ] . material
path = os . path . join ( os . path . dirname ( __file__ ) , " resources/materials.blend " ) + " \\ Material \\ "
path = os . path . join ( os . path . dirname ( __file__ ) ,
" resources/materials.blend " ) + " \\ Material \\ "
if " bevel " in mode :
path = os . path . join ( os . path . dirname ( __file__ ) , " resources/materials_2.80.blend " ) + " \\ Material \\ "
path = os . path . join ( os . path . dirname ( __file__ ) ,
" resources/materials_2.80.blend " ) + " \\ Material \\ "
print ( " Get mat {} \n {} " . format ( mode , path ) )
if bpy . data . materials . get ( name ) is None :
print ( " Material not yet loaded: " + mode )
bpy . ops . wm . append ( filename = name , directory = path , link = False , autoselect = False )
bpy . ops . wm . append ( filename = name , directory = path ,
link = False , autoselect = False )
return bpy . data . materials . get ( name )
def cycles_bake ( mode , padding , sampling_scale , samples , ray_distance , is_multi , obj_cage ) :
# if modes[mode].engine == 'BLENDER_EEVEE':
# # Snippet: https://gist.github.com/AndrewRayCode/760c4634a77551827de41ed67585064b
# bpy.context.scene.render.bake_margin = padding
@ -518,7 +510,6 @@ def cycles_bake(mode, padding, sampling_scale, samples, ray_distance, is_multi,
# bpy.ops.object.bake_image()
if modes [ mode ] . engine == ' CYCLES ' or modes [ mode ] . engine == ' BLENDER_EEVEE ' :
if modes [ mode ] . normal_space == ' OBJECT ' :
@ -578,4 +569,15 @@ def cycles_bake(mode, padding, sampling_scale, samples, ray_distance, is_multi,
cage_object = obj_cage . name
)
bpy . utils . register_class ( op )
use_selected_to_active = is_multi ,
normal_space = modes [ mode ] . normal_space ,
# Use Cage and assign object
use_cage = True ,
cage_object = obj_cage . name
)
bpy . utils . register_class ( op )