Update lightmapper to v0.6

master
Alexander Kleemann 2022-01-13 18:59:25 +01:00
parent f775305b64
commit 3ab8b81d66
25 changed files with 2506 additions and 492 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,7 @@
from . import keymap
def register():
keymap.register()
def unregister():
keymap.unregister()

View File

@ -23,8 +23,21 @@ classes = [
tlm.TLM_CleanBuildEnvironmentProbes,
tlm.TLM_PrepareUVMaps,
tlm.TLM_LoadLightmaps,
tlm.TLM_DisableSpecularity,
tlm.TLM_DisableMetallic,
tlm.TLM_RemoveEmptyImages,
tlm.TLM_AddCollectionsPost,
tlm.TLM_AddSelectedCollectionsPost,
tlm.TLM_PostAtlasSpecialsMenu,
tlm.TLM_AddCollections,
tlm.TLM_AddSelectedCollections,
tlm.TLM_AtlasSpecialsMenu,
tlm.TLM_Reset,
tlm.TLM_CalcTexDex,
imagetools.TLM_ImageUpscale,
imagetools.TLM_ImageDownscale
imagetools.TLM_ImageDownscale,
tlm.TLM_AddGLTFNode,
tlm.TLM_ShiftMultiplyLinks
]

View File

@ -29,7 +29,7 @@ class TLM_Install_OpenCV(bpy.types.Operator):
if platform.system() == "Windows":
pythonlibpath = os.path.join(os.path.dirname(os.path.dirname(pythonbinpath)), "lib")
else:
pythonlibpath = os.path.join(os.path.dirname(os.path.dirname(pythonbinpath)), "lib", os.path.basename(pythonbinpath)[:-1])
pythonlibpath = os.path.join(os.path.dirname(os.path.dirname(pythonbinpath)), "lib", os.path.basename(pythonbinpath))
ensurepippath = os.path.join(pythonlibpath, "ensurepip")
@ -78,4 +78,4 @@ class TLM_Install_OpenCV(bpy.types.Operator):
print("Sucessfully installed OpenCV!\n")
ShowMessageBox("Please restart blender to enable OpenCV filtering", "Restart", 'PREFERENCES')
return{'FINISHED'}
return{'FINISHED'}

View File

@ -75,9 +75,11 @@ class TLM_CleanLightmaps(bpy.types.Operator):
filepath = bpy.data.filepath
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), scene.TLM_EngineProperties.tlm_lightmap_savedir)
if os.path.isdir(dirpath):
for file in os.listdir(dirpath):
os.remove(os.path.join(dirpath + "/" + file))
if not bpy.context.scene.TLM_SceneProperties.tlm_keep_baked_files:
if os.path.isdir(dirpath):
for file in os.listdir(dirpath):
os.remove(os.path.join(dirpath + "/" + file))
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
@ -89,6 +91,13 @@ class TLM_CleanLightmaps(bpy.types.Operator):
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
cache.backup_material_rename(obj)
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
for vertex_layer in obj.data.vertex_colors:
if vertex_layer.name == "TLM":
obj.data.vertex_colors.remove(vertex_layer)
for mat in bpy.data.materials:
if mat.users < 1:
bpy.data.materials.remove(mat)
@ -146,6 +155,27 @@ class TLM_CleanLightmaps(bpy.types.Operator):
if "Lightmap" in obj:
del obj["Lightmap"]
if bpy.context.scene.TLM_SceneProperties.tlm_repartition_on_clean:
mats = bpy.data.materials
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
print("Repartitioning materials")
for slt in obj.material_slots:
print("Repartitioning material: " + str(slt.name))
part = slt.name.rpartition('.')
if part[2].isnumeric() and part[0] in mats:
slt.material = mats.get(part[0])
for slt in obj.material_slots:
if slt.name.endswith(tuple(["001","002","003","004","005","006","007","008","009"])): #Do regex instead
if not slt.name[:-4] in mats:
slt.material.name = slt.name[:-4]
return {'FINISHED'}
class TLM_ExploreLightmaps(bpy.types.Operator):
@ -484,6 +514,19 @@ class TLM_SelectLightmapped(bpy.types.Operator):
return{'FINISHED'}
class TLM_GroupListNewItem(bpy.types.Operator):
# Add a new item to the list
bl_idname = "tlm_grouplist.new_item"
bl_label = "Add a new lightmap group"
bl_description = "Create a new lightmap group"
def execute(self, context):
scene = context.scene
scene.TLM_GroupList.add()
scene.TLM_GroupListItem = len(scene.TLM_GroupList) - 1
scene.TLM_GroupList[len(scene.TLM_GroupList) - 1].name = "LightmapGroup"
class TLM_AtlasListNewItem(bpy.types.Operator):
# Add a new item to the list
bl_idname = "tlm_atlaslist.new_item"
@ -952,8 +995,6 @@ class TLM_PrepareUVMaps(bpy.types.Operator):
scene = context.scene
return {'FINISHED'}
class TLM_LoadLightmaps(bpy.types.Operator):
@ -968,7 +1009,9 @@ class TLM_LoadLightmaps(bpy.types.Operator):
utility.transfer_load()
build.finish_assemble()
print("Transfer finished")
build.finish_assemble(self, 1, 1)
return {'FINISHED'}
@ -1029,6 +1072,582 @@ class TLM_ToggleTexelDensity(bpy.types.Operator):
return {'FINISHED'}
class TLM_DisableSpecularity(bpy.types.Operator):
bl_idname = "tlm.disable_specularity"
bl_label = "Disable specularity"
bl_description = "Disables specularity from set"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene":
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
for slot in obj.material_slots:
mat = slot.material
if mat.node_tree:
for node in mat.node_tree.nodes:
if node.type == "BSDF_PRINCIPLED":
for inp in node.inputs:
if inp.name == "Specular":
inp.default_value = 0.0
if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link:
mat.node_tree.links.remove(inp.links[0])
elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection":
for obj in bpy.context.selected_objects:
if obj.type == "MESH":
for slot in obj.material_slots:
mat = slot.material
if mat.node_tree:
for node in mat.node_tree.nodes:
if node.type == "BSDF_PRINCIPLED":
for inp in node.inputs:
if inp.name == "Specular":
inp.default_value = 0.0
if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link:
mat.node_tree.links.remove(inp.links[0])
else: #Enabled
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
for slot in obj.material_slots:
mat = slot.material
if mat.node_tree:
for node in mat.node_tree.nodes:
if node.type == "BSDF_PRINCIPLED":
for inp in node.inputs:
if inp.name == "Specular":
inp.default_value = 0.0
if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link:
mat.node_tree.links.remove(inp.links[0])
return{'FINISHED'}
class TLM_DisableMetallic(bpy.types.Operator):
bl_idname = "tlm.disable_metallic"
bl_label = "Disable metallic"
bl_description = "Disables metallic from set"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene":
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
for slot in obj.material_slots:
mat = slot.material
for node in mat.node_tree.nodes:
if node.type == "BSDF_PRINCIPLED":
for inp in node.inputs:
if inp.name == "Metallic":
inp.default_value = 0.0
if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link:
mat.node_tree.links.remove(inp.links[0])
elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection":
for obj in bpy.context.selected_objects:
if obj.type == "MESH":
for slot in obj.material_slots:
mat = slot.material
for node in mat.node_tree.nodes:
if node.type == "BSDF_PRINCIPLED":
for inp in node.inputs:
if inp.name == "Metallic":
inp.default_value = 0.0
if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link:
mat.node_tree.links.remove(inp.links[0])
else: #Enabled
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
for slot in obj.material_slots:
mat = slot.material
for node in mat.node_tree.nodes:
if node.type == "BSDF_PRINCIPLED":
for inp in node.inputs:
if inp.name == "Metallic":
inp.default_value = 0.0
if inp.links and bpy.context.scene.TLM_SceneProperties.tlm_remove_met_spec_link:
mat.node_tree.links.remove(inp.links[0])
return{'FINISHED'}
class TLM_RemoveEmptyImages(bpy.types.Operator):
bl_idname = "tlm.remove_empty_images"
bl_label = "Remove Empty Images"
bl_description = "Removes empty images from scene materials"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
for mat in bpy.data.materials:
nodetree = mat.node_tree
if nodetree:
for node in nodetree.nodes:
if node.name == "Baked Image":
print(node.name)
nodetree.nodes.remove(node)
return{'FINISHED'}
class TLM_PostAtlasSpecialsMenu(bpy.types.Menu):
bl_label = "Lightmap"
bl_idname = "TLM_MT_PostAtlasListSpecials"
def draw(self, context):
layout = self.layout
layout.operator("tlm.add_collections_post")
layout.operator("tlm.add_selected_collections_post")
class TLM_AddCollectionsPost(bpy.types.Operator):
bl_idname = "tlm.add_collections_post"
bl_label = "Add collections"
bl_description = "Adds all collections to atlases"
bl_options = {'REGISTER', 'UNDO'}
resolution : bpy.props.EnumProperty(
items = [('32', '32', 'TODO'),
('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO'),
('8192', '8192', 'TODO')],
name = "Atlas Lightmap Resolution",
description="Atlas lightmap resolution",
default='256')
unwrap_modes = [('Lightmap', 'Lightmap', 'Use Blender Lightmap Pack algorithm'),
('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm')]
if "blender_xatlas" in bpy.context.preferences.addons.keys():
unwrap_modes.append(('Xatlas', 'Xatlas', 'Use Xatlas addon packing algorithm'))
unwrap : bpy.props.EnumProperty(
items = unwrap_modes,
name = "Unwrap Mode",
description="Atlas unwrapping method",
default='SmartProject')
margin : bpy.props.FloatProperty(
name="Unwrap Margin",
default=0.1,
min=0.0,
max=1.0,
subtype='FACTOR')
@classmethod
def poll(cls, context):
return True
def execute(self, context):
for collection in bpy.context.scene.collection.children:
#Add a new atlas with collection name
#Traverse before adding
scene = bpy.context.scene
scene.TLM_PostAtlasList.add()
scene.TLM_PostAtlasListItem = len(scene.TLM_PostAtlasList) - 1
scene.TLM_PostAtlasList[len(scene.TLM_PostAtlasList) - 1].name = collection.name
scene.TLM_PostAtlasList[collection.name].tlm_atlas_lightmap_unwrap_mode = self.unwrap
scene.TLM_PostAtlasList[collection.name].tlm_atlas_lightmap_resolution = self.resolution
scene.TLM_PostAtlasList[collection.name].tlm_atlas_unwrap_margin = self.margin
for obj in collection.objects:
if obj.type == "MESH":
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True
obj.TLM_ObjectProperties.tlm_postpack_object = True
obj.TLM_ObjectProperties.tlm_postatlas_pointer = collection.name
return{'FINISHED'}
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
row = self.layout
row.prop(self, "unwrap", text="Unwrap mode")
row.prop(self, "resolution", text="Resolution")
row.prop(self, "margin", text="Margin")
class TLM_AddSelectedCollectionsPost(bpy.types.Operator):
bl_idname = "tlm.add_selected_collections_post"
bl_label = "Add selected collections"
bl_description = "Add the collections of the selected objects"
bl_options = {'REGISTER', 'UNDO'}
resolution : bpy.props.EnumProperty(
items = [('32', '32', 'TODO'),
('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO'),
('8192', '8192', 'TODO')],
name = "Atlas Lightmap Resolution",
description="Atlas lightmap resolution",
default='256')
unwrap_modes = [('Lightmap', 'Lightmap', 'Use Blender Lightmap Pack algorithm'),
('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm')]
if "blender_xatlas" in bpy.context.preferences.addons.keys():
unwrap_modes.append(('Xatlas', 'Xatlas', 'Use Xatlas addon packing algorithm'))
unwrap : bpy.props.EnumProperty(
items = unwrap_modes,
name = "Unwrap Mode",
description="Atlas unwrapping method",
default='SmartProject')
margin : bpy.props.FloatProperty(
name="Unwrap Margin",
default=0.1,
min=0.0,
max=1.0,
subtype='FACTOR')
@classmethod
def poll(cls, context):
return True
def execute(self, context):
collections = []
for obj in bpy.context.selected_objects:
obj_collection = obj.users_collection[0]
if obj_collection.name not in collections:
collections.append(obj_collection.name)
print("Collections:" + str(collections))
for collection in bpy.context.scene.collection.children:
if collection.name in collections:
#Add a new atlas with collection name
#Traverse before adding
scene = bpy.context.scene
scene.TLM_PostAtlasList.add()
scene.TLM_PostAtlasListItem = len(scene.TLM_PostAtlasList) - 1
scene.TLM_PostAtlasList[len(scene.TLM_PostAtlasList) - 1].name = collection.name
scene.TLM_PostAtlasList[collection.name].tlm_atlas_lightmap_unwrap_mode = self.unwrap
scene.TLM_PostAtlasList[collection.name].tlm_atlas_lightmap_resolution = self.resolution
scene.TLM_PostAtlasList[collection.name].tlm_atlas_unwrap_margin = self.margin
for obj in collection.objects:
if obj.type == "MESH":
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True
obj.TLM_ObjectProperties.tlm_postpack_object = True
obj.TLM_ObjectProperties.tlm_postatlas_pointer = collection.name
return{'FINISHED'}
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
row = self.layout
row.prop(self, "unwrap", text="Unwrap mode")
row.prop(self, "resolution", text="Resolution")
row.prop(self, "margin", text="Margin")
class TLM_AtlasSpecialsMenu(bpy.types.Menu):
bl_label = "Lightmap"
bl_idname = "TLM_MT_AtlasListSpecials"
def draw(self, context):
layout = self.layout
layout.operator("tlm.add_collections")
layout.operator("tlm.add_selected_collections")
class TLM_AddCollections(bpy.types.Operator):
bl_idname = "tlm.add_collections"
bl_label = "Add all collections"
bl_description = "Adds all collections to atlases"
bl_options = {'REGISTER', 'UNDO'}
resolution : bpy.props.EnumProperty(
items = [('32', '32', 'TODO'),
('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO'),
('8192', '8192', 'TODO')],
name = "Atlas Lightmap Resolution",
description="Atlas lightmap resolution",
default='256')
unwrap_modes = [('Lightmap', 'Lightmap', 'Use Blender Lightmap Pack algorithm'),
('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm'),
('Copy', 'Copy existing', 'Use the existing UV channel')]
if "blender_xatlas" in bpy.context.preferences.addons.keys():
unwrap_modes.append(('Xatlas', 'Xatlas', 'Use Xatlas addon packing algorithm'))
unwrap : bpy.props.EnumProperty(
items = unwrap_modes,
name = "Unwrap Mode",
description="Atlas unwrapping method",
default='SmartProject')
margin : bpy.props.FloatProperty(
name="Unwrap Margin",
default=0.1,
min=0.0,
max=1.0,
subtype='FACTOR')
@classmethod
def poll(cls, context):
return True
def execute(self, context):
for collection in bpy.context.scene.collection.children:
#Add a new atlas with collection name
#Traverse before adding
scene = bpy.context.scene
scene.TLM_AtlasList.add()
scene.TLM_AtlasListItem = len(scene.TLM_AtlasList) - 1
scene.TLM_AtlasList[len(scene.TLM_AtlasList) - 1].name = collection.name
scene.TLM_AtlasList[collection.name].tlm_atlas_lightmap_unwrap_mode = self.unwrap
scene.TLM_AtlasList[collection.name].tlm_atlas_lightmap_resolution = self.resolution
scene.TLM_AtlasList[collection.name].tlm_atlas_unwrap_margin = self.margin
for obj in collection.objects:
if obj.type == "MESH":
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True
obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = "AtlasGroupA"
obj.TLM_ObjectProperties.tlm_atlas_pointer = collection.name
return{'FINISHED'}
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
row = self.layout
row.prop(self, "unwrap", text="Unwrap mode")
row.prop(self, "resolution", text="Resolution")
row.prop(self, "margin", text="Margin")
class TLM_AddSelectedCollections(bpy.types.Operator):
bl_idname = "tlm.add_selected_collections"
bl_label = "Add the collections of the selected objects"
bl_description = "Add the collections of the selected objects"
bl_options = {'REGISTER', 'UNDO'}
resolution : bpy.props.EnumProperty(
items = [('32', '32', 'TODO'),
('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO'),
('8192', '8192', 'TODO')],
name = "Atlas Lightmap Resolution",
description="Atlas lightmap resolution",
default='256')
unwrap_modes = [('Lightmap', 'Lightmap', 'Use Blender Lightmap Pack algorithm'),
('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm'),
('Copy', 'Copy existing', 'Use the existing UV channel')]
if "blender_xatlas" in bpy.context.preferences.addons.keys():
unwrap_modes.append(('Xatlas', 'Xatlas', 'Use Xatlas addon packing algorithm'))
unwrap : bpy.props.EnumProperty(
items = unwrap_modes,
name = "Unwrap Mode",
description="Atlas unwrapping method",
default='SmartProject')
margin : bpy.props.FloatProperty(
name="Unwrap Margin",
default=0.1,
min=0.0,
max=1.0,
subtype='FACTOR')
@classmethod
def poll(cls, context):
return True
def execute(self, context):
collections = []
for obj in bpy.context.selected_objects:
obj_collection = obj.users_collection[0]
if obj_collection.name not in collections:
collections.append(obj_collection.name)
print("Collections:" + str(collections))
for collection in bpy.context.scene.collection.children:
if collection.name in collections:
#Add a new atlas with collection name
#Traverse before adding
scene = bpy.context.scene
scene.TLM_AtlasList.add()
scene.TLM_AtlasListItem = len(scene.TLM_AtlasList) - 1
scene.TLM_AtlasList[len(scene.TLM_AtlasList) - 1].name = collection.name
scene.TLM_AtlasList[collection.name].tlm_atlas_lightmap_unwrap_mode = self.unwrap
scene.TLM_AtlasList[collection.name].tlm_atlas_lightmap_resolution = self.resolution
scene.TLM_AtlasList[collection.name].tlm_atlas_unwrap_margin = self.margin
for obj in collection.objects:
if obj.type == "MESH":
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True
obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = "AtlasGroupA"
obj.TLM_ObjectProperties.tlm_atlas_pointer = collection.name
return{'FINISHED'}
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
row = self.layout
row.prop(self, "unwrap", text="Unwrap mode")
row.prop(self, "resolution", text="Resolution")
row.prop(self, "margin", text="Margin")
#Atlas disable objects
class TLM_Reset(bpy.types.Operator):
bl_idname = "tlm.reset"
bl_label = "Resets all UI and settings"
bl_description = "Reset UI and objects"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
self.report({'INFO'}, "YES!")
return {'FINISHED'}
def invoke(self, context, event):
return context.window_manager.invoke_confirm(self, event)
# class TLM_Reset2(bpy.types.Operator):
# bl_idname = "tlm.reset2"
# bl_label = "Do you really want to do that?"
# bl_options = {'REGISTER', 'INTERNAL'}
# prop1: bpy.props.BoolProperty()
# prop2: bpy.props.BoolProperty()
# @classmethod
# def poll(cls, context):
# return True
# def execute(self, context):
# self.report({'INFO'}, "YES!")
# return {'FINISHED'}
# def invoke(self, context, event):
# return context.window_manager.invoke_props_dialog(self)
# def draw(self, context):
# row = self.layout
# row.prop(self, "prop1", text="Property A")
# row.prop(self, "prop2", text="Property B")
def TLM_DoubleResolution():
pass
@ -1037,4 +1656,76 @@ def TLM_HalfResolution():
pass
def TLM_DivideLMGroups():
pass
pass
class TLM_CalcTexDex(bpy.types.Operator):
bl_idname = "tlm.calctexdex"
bl_label = "Calculate Texel Density"
bl_description = "Calculates Texel Density of selected object"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
return {'FINISHED'}
class TLM_AddGLTFNode(bpy.types.Operator):
bl_idname = "tlm.add_gltf_node"
bl_label = "Add GLTF Node"
bl_description = "Add to GLTF node to active material and connect lightmap if present"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
cycles = scene.cycles
material = bpy.context.active_object.active_material
nodes = material.node_tree.nodes
# create group data
gltf_settings = bpy.data.node_groups.get('glTF Settings')
if gltf_settings is None:
bpy.data.node_groups.new('glTF Settings', 'ShaderNodeTree')
# add group to node tree
gltf_settings_node = nodes.get('glTF Settings')
if gltf_settings_node is None:
gltf_settings_node = nodes.new('ShaderNodeGroup')
gltf_settings_node.name = 'glTF Settings'
gltf_settings_node.node_tree = bpy.data.node_groups['glTF Settings']
# create group inputs
if gltf_settings_node.inputs.get('Occlusion') is None:
gltf_settings_node.inputs.new('NodeSocketFloat','Occlusion')
#return gltf_settings_node
return {'FINISHED'}
class TLM_ShiftMultiplyLinks(bpy.types.Operator):
bl_idname = "tlm.shift_multiply_links"
bl_label = "Shift multiply links"
bl_description = "Shift multiply links for active material"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
cycles = scene.cycles
material = bpy.context.active_object.active_material
nodes = material.node_tree.nodes
LM_Node = nodes.get("TLM_Lightmap")
Multi_Node = nodes.get("Lightmap_Multiplication")
Base_Node = nodes.get("Lightmap_BasecolorNode_A")
material.node_tree.links.remove(LM_Node.outputs[0].links[0])
material.node_tree.links.remove(Base_Node.outputs[0].links[0])
material.node_tree.links.new(LM_Node.outputs[0], Multi_Node.inputs[2])
material.node_tree.links.new(Base_Node.outputs[0], Multi_Node.inputs[1])
return {'FINISHED'}

View File

@ -93,6 +93,14 @@ class TLM_PT_ObjectMenu(bpy.types.Panel):
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
#If UV Packer installed
if "UV-Packer" in bpy.context.preferences.addons.keys():
row.prop(obj.TLM_ObjectProperties, "tlm_use_uv_packer")
if obj.TLM_ObjectProperties.tlm_use_uv_packer:
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_uv_packer_padding")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_uv_packer_packing_engine")
class TLM_PT_MaterialMenu(bpy.types.Panel):
bl_label = "The Lightmapper"

View File

@ -4,6 +4,50 @@ from bpy.types import Menu, Panel
from .. utility import icon
from .. properties.denoiser import oidn, optix
class TLM_PT_Panel(bpy.types.Panel):
bl_label = "The Lightmapper"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
scene = context.scene
layout.use_property_split = True
layout.use_property_decorate = False
sceneProperties = scene.TLM_SceneProperties
class TLM_PT_Groups(bpy.types.Panel):
bl_label = "Lightmap Groups"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "TLM_PT_Panel"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.use_property_split = True
layout.use_property_decorate = False
sceneProperties = scene.TLM_SceneProperties
if sceneProperties.tlm_lightmap_engine == "Cycles":
rows = 2
#if len(atlasList) > 1:
# rows = 4
row = layout.row(align=True)
row.label(text="Lightmap Group List")
row = layout.row(align=True)
row.template_list("TLM_UL_GroupList", "Lightmap Groups", scene, "TLM_GroupList", scene, "TLM_GroupListItem", rows=rows)
col = row.column(align=True)
col.operator("tlm_atlaslist.new_item", icon='ADD', text="")
#col.operator("tlm_atlaslist.delete_item", icon='REMOVE', text="")
#col.menu("TLM_MT_AtlasListSpecials", icon='DOWNARROW_HLT', text="")
class TLM_PT_Settings(bpy.types.Panel):
bl_label = "Settings"
bl_space_type = "PROPERTIES"
@ -64,6 +108,14 @@ class TLM_PT_Settings(bpy.types.Panel):
row.prop(sceneProperties, "tlm_override_color")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_reset_uv")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_apply_modifiers")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_keep_baked_files")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_repartition_on_clean")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_save_preprocess_lightmaps")
row = layout.row(align=True)
try:
@ -259,9 +311,7 @@ class TLM_PT_Filtering(bpy.types.Panel):
if cv2 is None:
row = layout.row(align=True)
row.label(text="OpenCV is not installed. Please install it as an administrator.")
row = layout.row(align=True)
row.operator("tlm.install_opencv_lightmaps")
row.label(text="OpenCV is not installed. Install it through preferences.")
else:
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_mode")
@ -357,6 +407,9 @@ class TLM_PT_Encoding(bpy.types.Panel):
if sceneProperties.tlm_encoding_mode_b == "LogLuv" and sceneProperties.tlm_encoding_device == "GPU":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_decoder_setup")
if sceneProperties.tlm_decoder_setup:
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_split_premultiplied")
if sceneProperties.tlm_encoding_mode_b == "HDR":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_format")
@ -384,30 +437,183 @@ class TLM_PT_Utility(bpy.types.Panel):
row = layout.row(align=True)
row.label(text="Enable Lightmaps for set")
row = layout.row(align=True)
row.operator("tlm.enable_set")
row.prop(sceneProperties, "tlm_utility_context")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_utility_set")
row = layout.row(align=True)
#row.label(text="ABCD")
row.prop(sceneProperties, "tlm_mesh_lightmap_unwrap_mode")
if sceneProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if sceneProperties.tlm_utility_context == "SetBatching":
row.operator("tlm.enable_set")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_utility_set")
row = layout.row(align=True)
#row.label(text="ABCD")
row.prop(sceneProperties, "tlm_mesh_lightmap_unwrap_mode")
if sceneProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if scene.TLM_AtlasListItem >= 0 and len(scene.TLM_AtlasList) > 0:
row = layout.row()
item = scene.TLM_AtlasList[scene.TLM_AtlasListItem]
row.prop_search(sceneProperties, "tlm_atlas_pointer", scene, "TLM_AtlasList", text='Atlas Group')
else:
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
if scene.TLM_AtlasListItem >= 0 and len(scene.TLM_AtlasList) > 0:
row = layout.row()
item = scene.TLM_AtlasList[scene.TLM_AtlasListItem]
row.prop_search(sceneProperties, "tlm_atlas_pointer", scene, "TLM_AtlasList", text='Atlas Group')
else:
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
else:
row = layout.row()
row.prop(sceneProperties, "tlm_postpack_object")
row = layout.row()
if sceneProperties.tlm_postpack_object and sceneProperties.tlm_mesh_lightmap_unwrap_mode != "AtlasGroupA":
if scene.TLM_PostAtlasListItem >= 0 and len(scene.TLM_PostAtlasList) > 0:
row = layout.row()
item = scene.TLM_PostAtlasList[scene.TLM_PostAtlasListItem]
row.prop_search(sceneProperties, "tlm_postatlas_pointer", scene, "TLM_PostAtlasList", text='Atlas Group')
row = layout.row()
else:
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_unwrap_margin")
row = layout.row()
row.prop(sceneProperties, "tlm_resolution_weight")
if sceneProperties.tlm_resolution_weight == "Single":
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_lightmap_resolution")
else:
row = layout.row()
row.prop(sceneProperties, "tlm_resolution_min")
row = layout.row()
row.prop(sceneProperties, "tlm_resolution_max")
row = layout.row()
row.prop(sceneProperties, "tlm_postpack_object")
row = layout.row()
row.operator("tlm.disable_selection")
row = layout.row(align=True)
row.operator("tlm.select_lightmapped_objects")
row = layout.row(align=True)
row.operator("tlm.remove_uv_selection")
if sceneProperties.tlm_postpack_object and sceneProperties.tlm_mesh_lightmap_unwrap_mode != "AtlasGroupA":
elif sceneProperties.tlm_utility_context == "EnvironmentProbes":
row.label(text="Environment Probes")
row = layout.row()
row.operator("tlm.build_environmentprobe")
row = layout.row()
row.operator("tlm.clean_environmentprobe")
row = layout.row()
row.prop(sceneProperties, "tlm_environment_probe_engine")
row = layout.row()
row.prop(sceneProperties, "tlm_cmft_path")
row = layout.row()
row.prop(sceneProperties, "tlm_environment_probe_resolution")
row = layout.row()
row.prop(sceneProperties, "tlm_create_spherical")
if sceneProperties.tlm_create_spherical:
row = layout.row()
row.prop(sceneProperties, "tlm_invert_direction")
row = layout.row()
row.prop(sceneProperties, "tlm_write_sh")
row = layout.row()
row.prop(sceneProperties, "tlm_write_radiance")
elif sceneProperties.tlm_utility_context == "LoadLightmaps":
row = layout.row(align=True)
row.label(text="Load lightmaps")
row = layout.row()
row.prop(sceneProperties, "tlm_load_folder")
row = layout.row()
row.operator("tlm.load_lightmaps")
row = layout.row()
row.prop(sceneProperties, "tlm_load_atlas")
elif sceneProperties.tlm_utility_context == "MaterialAdjustment":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_utility_set")
row = layout.row(align=True)
row.operator("tlm.disable_specularity")
row.operator("tlm.disable_metallic")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_remove_met_spec_link")
row = layout.row(align=True)
row.operator("tlm.remove_empty_images")
row = layout.row(align=True)
elif sceneProperties.tlm_utility_context == "NetworkRender":
row.label(text="Network Rendering")
row = layout.row()
row.operator("tlm.start_server")
layout.label(text="Atlas Groups")
elif sceneProperties.tlm_utility_context == "TexelDensity":
row.label(text="Texel Density Utilies")
row = layout.row()
elif sceneProperties.tlm_utility_context == "GLTFUtil":
row.label(text="GLTF material utilities")
row = layout.row()
row.operator("tlm.add_gltf_node")
row = layout.row()
row.operator("tlm.shift_multiply_links")
class TLM_PT_Selection(bpy.types.Panel):
bl_label = "Selection"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_BakePanel"
@classmethod
def poll(self, context):
scene = context.scene
return scene.arm_bakemode == "Lightmap"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.use_property_split = True
layout.use_property_decorate = False
sceneProperties = scene.TLM_SceneProperties
row = layout.row(align=True)
row.operator("tlm.enable_selection")
row = layout.row(align=True)
row.operator("tlm.disable_selection")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_override_object_settings")
if sceneProperties.tlm_override_object_settings:
row = layout.row(align=True)
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_lightmap_unwrap_mode")
row = layout.row()
if sceneProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if scene.TLM_AtlasListItem >= 0 and len(scene.TLM_AtlasList) > 0:
row = layout.row()
item = scene.TLM_AtlasList[scene.TLM_AtlasListItem]
row.prop_search(sceneProperties, "tlm_atlas_pointer", scene, "TLM_AtlasList", text='Atlas Group')
else:
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
else:
row = layout.row()
row.prop(sceneProperties, "tlm_postpack_object")
row = layout.row()
if sceneProperties.tlm_postpack_object and sceneProperties.tlm_mesh_lightmap_unwrap_mode != "AtlasGroupA":
if scene.TLM_PostAtlasListItem >= 0 and len(scene.TLM_PostAtlasList) > 0:
row = layout.row()
item = scene.TLM_PostAtlasList[scene.TLM_PostAtlasListItem]
@ -418,57 +624,20 @@ class TLM_PT_Utility(bpy.types.Panel):
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_unwrap_margin")
row = layout.row()
row.prop(sceneProperties, "tlm_resolution_weight")
if sceneProperties.tlm_resolution_weight == "Single":
row = layout.row()
if sceneProperties.tlm_mesh_lightmap_unwrap_mode != "AtlasGroupA":
row.prop(sceneProperties, "tlm_mesh_lightmap_resolution")
else:
row = layout.row()
row.prop(sceneProperties, "tlm_resolution_min")
row = layout.row()
row.prop(sceneProperties, "tlm_resolution_max")
row.prop(sceneProperties, "tlm_mesh_unwrap_margin")
row = layout.row()
row.operator("tlm.disable_selection")
row = layout.row(align=True)
row.operator("tlm.select_lightmapped_objects")
row = layout.row(align=True)
row.operator("tlm.remove_uv_selection")
row = layout.row(align=True)
row.label(text="Environment Probes")
row = layout.row()
row.operator("tlm.build_environmentprobe")
row = layout.row()
row.operator("tlm.clean_environmentprobe")
row = layout.row()
row.prop(sceneProperties, "tlm_environment_probe_engine")
row = layout.row()
row.prop(sceneProperties, "tlm_cmft_path")
row = layout.row()
row.prop(sceneProperties, "tlm_environment_probe_resolution")
row = layout.row()
row.prop(sceneProperties, "tlm_create_spherical")
if sceneProperties.tlm_create_spherical:
row = layout.row()
row.prop(sceneProperties, "tlm_invert_direction")
row = layout.row()
row.prop(sceneProperties, "tlm_write_sh")
row = layout.row()
row.prop(sceneProperties, "tlm_write_radiance")
row = layout.row(align=True)
row.label(text="Load lightmaps")
row = layout.row()
row.prop(sceneProperties, "tlm_load_folder")
row = layout.row()
row.operator("tlm.load_lightmaps")
row.operator("tlm.select_lightmapped_objects")
# row = layout.row(align=True)
# for addon in bpy.context.preferences.addons.keys():
# if addon.startswith("Texel_Density"):
# row.operator("tlm.toggle_texel_density")
# row = layout.row(align=True)
class TLM_PT_Additional(bpy.types.Panel):
bl_label = "Additional"
@ -492,10 +661,6 @@ class TLM_PT_Additional(bpy.types.Panel):
postatlasListItem = scene.TLM_PostAtlasListItem
postatlasList = scene.TLM_PostAtlasList
layout.label(text="Network Rendering")
row = layout.row()
row.operator("tlm.start_server")
layout.label(text="Atlas Groups")
row = layout.row()
row.prop(sceneProperties, "tlm_atlas_mode", expand=True)
@ -509,6 +674,7 @@ class TLM_PT_Additional(bpy.types.Panel):
col = row.column(align=True)
col.operator("tlm_atlaslist.new_item", icon='ADD', text="")
col.operator("tlm_atlaslist.delete_item", icon='REMOVE', text="")
col.menu("TLM_MT_AtlasListSpecials", icon='DOWNARROW_HLT', text="")
if atlasListItem >= 0 and len(atlasList) > 0:
item = atlasList[atlasListItem]
@ -525,6 +691,11 @@ class TLM_PT_Additional(bpy.types.Panel):
amount = amount + 1
layout.label(text="Objects: " + str(amount))
layout.prop(item, "tlm_atlas_merge_samemat")
layout.prop(item, "tlm_use_uv_packer")
layout.prop(item, "tlm_uv_packer_padding")
layout.prop(item, "tlm_uv_packer_packing_engine")
else:
@ -547,6 +718,7 @@ class TLM_PT_Additional(bpy.types.Panel):
col = row.column(align=True)
col.operator("tlm_postatlaslist.new_item", icon='ADD', text="")
col.operator("tlm_postatlaslist.delete_item", icon='REMOVE', text="")
col.menu("TLM_MT_PostAtlasListSpecials", icon='DOWNARROW_HLT', text="")
if postatlasListItem >= 0 and len(postatlasList) > 0:
item = postatlasList[postatlasListItem]
@ -581,4 +753,4 @@ class TLM_PT_Additional(bpy.types.Panel):
layout.label(text="Utilized: " + str(utilized * 100) + "%")
if (utilized * 100) > 100:
layout.label(text="Warning! Overflow not yet supported")
layout.label(text="Warning! Overflow not yet supported")

View File

@ -1,12 +1,19 @@
import bpy, platform
from os.path import basename, dirname
from bpy.types import AddonPreferences
from bpy.props import *
from .. operators import installopencv
from . import addon_preferences
import importlib
class TLM_AddonPreferences(AddonPreferences):
bl_idname = "thelightmapper"
bl_idname = __name__.split(".")[0]
tlm_ui_mode: EnumProperty(
items=[('simple', 'Simple', 'Simple UI'),
('advanced', 'Advanced', 'Advanced UI')],
name='UI mode', default='simple', description='Choose UI mode')
def draw(self, context):
@ -14,6 +21,15 @@ class TLM_AddonPreferences(AddonPreferences):
box = layout.box()
row = box.row()
row.label(text="UI Mode")
row.prop(self, "tlm_ui_mode")
row = box.row()
row.label(text="Simple: Only the basic setup for Blender/Eevee baking with non-experimental features.")
row = box.row()
row.label(text="Full set of options available.")
row = box.row()
row.label(text="OpenCV")
cv2 = importlib.util.find_spec("cv2")
@ -48,6 +64,21 @@ class TLM_AddonPreferences(AddonPreferences):
row.label(text="UVPackmaster")
row.label(text="Coming soon")
uvpacker_addon = False
for addon in bpy.context.preferences.addons.keys():
if addon.startswith("UV-Packer"):
uvpacker_addon = True
box = layout.box()
row = box.row()
row.label(text="UV Packer")
if uvpacker_addon:
row.label(text="UV Packer installed and available")
else:
row.label(text="UV Packer not installed", icon_value=2)
row = box.row()
row.label(text="Github: https://www.uv-packer.com/blender/")
texel_density_addon = False
for addon in bpy.context.preferences.addons.keys():
if addon.startswith("Texel_Density"):

View File

@ -16,7 +16,9 @@ classes = [
atlas.TLM_UL_AtlasList,
atlas.TLM_PostAtlasListItem,
atlas.TLM_UL_PostAtlasList,
image.TLM_ImageProperties
image.TLM_ImageProperties,
scene.TLM_UL_GroupList,
scene.TLM_GroupListItem
]
def register():
@ -35,6 +37,8 @@ def register():
bpy.types.Scene.TLM_PostAtlasListItem = bpy.props.IntProperty(name="Index for my_list", default=0)
bpy.types.Scene.TLM_PostAtlasList = bpy.props.CollectionProperty(type=atlas.TLM_PostAtlasListItem)
bpy.types.Image.TLM_ImageProperties = bpy.props.PointerProperty(type=image.TLM_ImageProperties)
bpy.types.Scene.TLM_GroupListItem = bpy.props.IntProperty(name="Index for my_list", default=0)
bpy.types.Scene.TLM_GroupList = bpy.props.CollectionProperty(type=scene.TLM_GroupListItem)
bpy.types.Material.TLM_ignore = bpy.props.BoolProperty(name="Skip material", description="Ignore material for lightmapped object", default=False)
@ -53,4 +57,6 @@ def unregister():
del bpy.types.Scene.TLM_AtlasList
del bpy.types.Scene.TLM_PostAtlasListItem
del bpy.types.Scene.TLM_PostAtlasList
del bpy.types.Image.TLM_ImageProperties
del bpy.types.Image.TLM_ImageProperties
del bpy.types.Scene.TLM_GroupListItem
del bpy.types.Scene.TLM_GroupList

View File

@ -35,11 +35,17 @@ class TLM_PostAtlasListItem(bpy.types.PropertyGroup):
subtype='FACTOR')
unwrap_modes = [('Lightmap', 'Lightmap', 'Use Blender Lightmap Pack algorithm'),
('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm')]
('SmartProject', 'Smart Project', 'Use Blender Smart Project algorithm'),
('Copy', 'Copy existing', 'Use the existing UV channel')]
if "blender_xatlas" in bpy.context.preferences.addons.keys():
unwrap_modes.append(('Xatlas', 'Xatlas', 'Use Xatlas addon packing algorithm'))
tlm_atlas_merge_samemat : BoolProperty(
name="Merge materials",
description="Merge objects with same materials.",
default=True)
tlm_postatlas_lightmap_unwrap_mode : EnumProperty(
items = unwrap_modes,
name = "Unwrap Mode",
@ -109,6 +115,30 @@ class TLM_AtlasListItem(bpy.types.PropertyGroup):
description="Atlas unwrapping method",
default='SmartProject')
tlm_atlas_merge_samemat : BoolProperty(
name="Merge materials",
description="Merge objects with same materials.",
default=True)
tlm_use_uv_packer : BoolProperty(
name="Use UV Packer",
description="UV Packer will be utilized after initial UV mapping for optimized packing.",
default=False)
tlm_uv_packer_padding : FloatProperty(
name="Padding",
default=2.0,
min=0.0,
max=100.0,
subtype='FACTOR')
tlm_uv_packer_packing_engine : EnumProperty(
items = [('OP0', 'Efficient', 'Best compromise for speed and space usage.'),
('OP1', 'High Quality', 'Slowest, but maximum space usage.')],
name = "Packing Engine",
description="Which UV Packer engine to use.",
default='OP0')
class TLM_UL_AtlasList(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
custom_icon = 'OBJECT_DATAMODE'

View File

@ -51,7 +51,8 @@ class TLM_ObjectProperties(bpy.types.PropertyGroup):
unwrap_modes = [('Lightmap', 'Lightmap', 'TODO'),
('SmartProject', 'Smart Project', 'TODO'),
('AtlasGroupA', 'Atlas Group (Prepack)', 'Attaches the object to a prepack Atlas group. Will overwrite UV map on build.')]
('AtlasGroupA', 'Atlas Group (Prepack)', 'Attaches the object to a prepack Atlas group. Will overwrite UV map on build.'),
('Copy', 'Copy existing', 'Use the existing UV channel')]
tlm_postpack_object : BoolProperty( #CHECK INSTEAD OF ATLASGROUPB
name="Postpack object",
@ -154,4 +155,28 @@ class TLM_ObjectProperties(bpy.types.PropertyGroup):
tlm_uv_channel : StringProperty(
name = "UV Channel",
description = "Use any custom UV Channel for the lightmap",
default = "UVMap")
default = "UVMap")
tlm_use_uv_packer : BoolProperty(
name="Use UV Packer",
description="UV Packer will be utilized after initial UV mapping for optimized packing.",
default=False)
tlm_uv_packer_padding : FloatProperty(
name="Padding",
default=2.0,
min=0.0,
max=100.0,
subtype='FACTOR')
tlm_uv_packer_packing_engine : EnumProperty(
items = [('OP0', 'Efficient', 'Best compromise for speed and space usage.'),
('OP1', 'High Quality', 'Slowest, but maximum space usage.')],
name = "Packing Engine",
description="Which UV Packer engine to use.",
default='OP0')
#Padding
#Type
#Rescale
#Pre-rotate

View File

@ -102,7 +102,7 @@ class TLM_CyclesSceneProperties(bpy.types.PropertyGroup):
items = [('combined', 'Combined', 'Bake combined lighting'),
('combinedao', 'Combined+AO', 'Bake combined lighting with Ambient Occlusion'),
('indirect', 'Indirect', 'Bake indirect lighting'),
# ('indirectao', 'Indirect+AO', 'Bake indirect lighting with Ambient Occlusion'),
('indirectao', 'Indirect+AO', 'Bake indirect lighting with Ambient Occlusion'),
('ao', 'AO', 'Bake only Ambient Occlusion'),
('complete', 'Complete', 'Bake complete map')],
name = "Lighting mode",

View File

@ -45,6 +45,16 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
description="Keep cache files (non-filtered and non-denoised)",
default=True)
tlm_keep_baked_files : BoolProperty(
name="Keep bake files",
description="Keep the baked lightmap files when cleaning",
default=False)
tlm_repartition_on_clean : BoolProperty(
name="Repartition on clean",
description="Repartition material names on clean",
default=False)
tlm_setting_renderer : EnumProperty(
items = [('CPU', 'CPU', 'Bake using the processor'),
('GPU', 'GPU', 'Bake using the graphics card')],
@ -103,6 +113,11 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
name="Apply scale",
description="TODO",
default=False)
tlm_save_preprocess_lightmaps : BoolProperty(
name="Save preprocessed lightmaps",
description="TODO",
default=False)
#DENOISE SETTINGS GROUP
tlm_denoise_use : BoolProperty(
@ -179,7 +194,7 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
max=100)
tlm_filtering_bilateral_coordinate_deviation : IntProperty(
name="Color deviation",
name="Coordinate deviation",
default=75,
min=1,
max=100)
@ -233,7 +248,7 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
tlm_encoding_mode_b : EnumProperty(
items = encoding_modes_2,
name = "Encoding Mode",
description="TODO",
description="RGBE 32-bit Radiance HDR File",
default='HDR')
tlm_encoding_range : IntProperty(
@ -245,7 +260,12 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
tlm_decoder_setup : BoolProperty(
name="Use decoder",
description="TODO",
description="Apply a node for decoding.",
default=False)
tlm_split_premultiplied : BoolProperty(
name="Split for premultiplied",
description="Some game engines doesn't support non-premultiplied files. This splits the alpha channel to a separate file.",
default=False)
tlm_encoding_colorspace : EnumProperty(
@ -385,6 +405,16 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
description="Remove existing UV maps for lightmaps.",
default=False)
tlm_apply_modifiers : BoolProperty(
name="Apply modifiers",
description="Apply all modifiers to objects.",
default=True)
tlm_batch_mode : BoolProperty(
name="Batch mode",
description="Batch collections.",
default=False)
tlm_network_render : BoolProperty(
name="Enable network rendering",
description="Enable network rendering (Unstable).",
@ -453,6 +483,11 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
description="Load existing lightmaps from folder",
subtype="DIR_PATH")
tlm_load_atlas : BoolProperty(
name="Load lightmaps based on atlas sets",
description="Use the current Atlas list.",
default=False)
tlm_utility_set : EnumProperty(
items = [('Scene', 'Scene', 'Set for all objects in the scene.'),
('Selection', 'Selection', 'Set for selected objects.'),
@ -494,4 +529,57 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
('4096', '4096', 'TODO')],
name = "Maximum resolution",
description="Maximum distributed resolution",
default='256')
default='256')
tlm_remove_met_spec_link : BoolProperty(
name="Remove image link",
description="Removes the connected node on metallic or specularity set disable",
default=False)
tlm_utility_context : EnumProperty(
items = [('SetBatching', 'Set Batching', 'Set batching options. Allows to set lightmap options for multiple objects.'),
('EnvironmentProbes', 'Environment Probes', 'Options for rendering environment probes. Cubemaps and panoramic HDRs for external engines'),
('LoadLightmaps', 'Load Lightmaps', 'Options for loading pre-built lightmaps.'),
('NetworkRender', 'Network Rendering', 'Distribute lightmap building across multiple machines.'),
('MaterialAdjustment', 'Material Adjustment', 'Allows adjustment of multiple materials at once.'),
('TexelDensity', 'Texel Density', 'Allows setting texel densities of the UV.'),
('GLTFUtil', 'GLTF Utilities', 'GLTF related material utilities.')],
name = "Utility Context",
description="Set Utility Context",
default='SetBatching')
tlm_addon_uimode : EnumProperty(
items = [('Simple', 'Simple', 'TODO'),
('Advanced', 'Advanced', 'TODO')],
name = "UI Mode",
description="TODO",
default='Simple')
class TLM_GroupListItem(bpy.types.PropertyGroup):
obj: PointerProperty(type=bpy.types.Object, description="The object to bake")
class TLM_UL_GroupList(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
custom_icon = 'OBJECT_DATAMODE'
if self.layout_type in {'DEFAULT', 'COMPACT'}:
amount = 0
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if obj.TLM_ObjectProperties.tlm_atlas_pointer == item.name:
amount = amount + 1
row = layout.row()
row.prop(item, "name", text="", emboss=False, icon=custom_icon)
col = row.column()
col.label(text=item.tlm_atlas_lightmap_resolution)
col = row.column()
col.alignment = 'RIGHT'
col.label(text=str(amount))
elif self.layout_type in {'GRID'}:
layout.alignment = 'CENTER'
layout.label(text="", icon = custom_icon)

View File

@ -1,6 +1,6 @@
import bpy, os, subprocess, sys, platform, aud, json, datetime, socket
from . import encoding, pack
from . import encoding, pack, log
from . cycles import lightmap, prepare, nodes, cache
from . luxcore import setup
from . octane import configure, lightmap2
@ -16,9 +16,15 @@ from importlib import util
previous_settings = {}
postprocess_shutdown = False
logging = True
def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
global tlm_log
tlm_log = log.TLM_Logman()
bpy.app.driver_namespace["logman"] = tlm_log
tlm_log.append("Preparing build")
if shutdown_after_build:
postprocess_shutdown = True
@ -46,29 +52,33 @@ def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
scene = bpy.context.scene
sceneProperties = scene.TLM_SceneProperties
if not background_mode and bpy.context.scene.TLM_EngineProperties.tlm_lighting_mode != "combinedao":
if not background_mode and bpy.context.scene.TLM_EngineProperties.tlm_lighting_mode != "combinedao" and bpy.context.scene.TLM_EngineProperties.tlm_lighting_mode != "indirectao":
#pass
setGui(1)
if check_save():
print("Please save your file first")
self.report({'INFO'}, "Please save your file first")
setGui(0)
return{'FINISHED'}
if check_denoiser():
print("No denoise OIDN path assigned")
self.report({'INFO'}, "No denoise OIDN path assigned")
self.report({'INFO'}, "No denoise OIDN path assigned. Check that it points to the correct executable.")
setGui(0)
return{'FINISHED'}
if check_materials():
print("Error with material")
self.report({'INFO'}, "Error with material")
setGui(0)
return{'FINISHED'}
if opencv_check():
if sceneProperties.tlm_filtering_use:
print("Error:Filtering - OpenCV not installed")
self.report({'INFO'}, "Error:Filtering - OpenCV not installed")
setGui(0)
return{'FINISHED'}
setMode()
@ -174,6 +184,7 @@ def distribute_building():
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("No process file - Creating one...")
tlm_log.append("No process file - Creating one...")
write_directory = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
@ -197,6 +208,7 @@ def distribute_building():
bpy.app.driver_namespace["tlm_process"] = subprocess.Popen([bpy.app.binary_path,"-b", blendPath,"--python-expr",'import bpy; import thelightmapper; thelightmapper.addon.utility.build.prepare_build(0, True);'], shell=False, stdout=subprocess.PIPE)
else:
bpy.app.driver_namespace["tlm_process"] = subprocess.Popen([bpy.app.binary_path,"-b", blendPath,"--python-expr",'import bpy; import thelightmapper; thelightmapper.addon.utility.build.prepare_build(0, True);'], shell=False, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
tlm_log.append("Started process: " + str(bpy.app.driver_namespace["tlm_process"]) + " at " + str(datetime.datetime.now()))
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Started process: " + str(bpy.app.driver_namespace["tlm_process"]) + " at " + str(datetime.datetime.now()))
@ -208,6 +220,7 @@ def distribute_building():
if process_status[1]["completed"]:
tlm_log.append("Baking finished from process. Status: Completed.")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Baking finished")
@ -218,21 +231,31 @@ def distribute_building():
else:
#Open the json and check the status!
tlm_log.append("Process check: Baking in progress.")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Baking in progress")
process_status = json.loads(open(os.path.join(write_directory, "process.tlm")).read())
tlm_log.append(process_status)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(process_status)
return 1.0
def finish_assemble(self=0):
def finish_assemble(self=0, background_pass=0, load_atlas=0):
print("Finishing assembly")
tlm_log = log.TLM_Logman()
tlm_log.append("Preparing build")
if load_atlas:
print("Assembly in Atlas load mode")
tlm_log.append("Assembly in Atlas load mode")
tlm_log.append("Background baking finished")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Background baking finished")
@ -253,7 +276,10 @@ def finish_assemble(self=0):
global start_time
start_time = time()
manage_build(True)
if background_pass:
manage_build(True, load_atlas)
else:
manage_build(False, load_atlas)
def begin_build():
@ -266,7 +292,18 @@ def begin_build():
if sceneProperties.tlm_lightmap_engine == "Cycles":
lightmap.bake()
try:
lightmap.bake()
except Exception as e:
print("An error occured during lightmap baking. See the line below for more detail:")
print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
tlm_log.append("An error occured during lightmap baking. See the line below for more detail:")
tlm_log.append(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
if not bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Turn on verbose mode to get more detail.")
if sceneProperties.tlm_lightmap_engine == "LuxCoreRender":
pass
@ -288,6 +325,7 @@ def begin_build():
if file.endswith("_baked.hdr"):
baked_image_array.append(file)
tlm_log.append(baked_image_array)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(baked_image_array)
@ -313,7 +351,18 @@ def begin_build():
denoiser = oidn.TLM_OIDN_Denoise(oidnProperties, baked_image_array, dirpath)
denoiser.denoise()
try:
denoiser.denoise()
except Exception as e:
print("An error occured during denoising. See the line below for more detail:")
print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
tlm_log.append("An error occured during denoising. See the line below for more detail:")
tlm_log.append(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
if not bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Turn on verbose mode to get more detail.")
denoiser.clean()
@ -349,7 +398,19 @@ def begin_build():
filter = opencv.TLM_CV_Filtering
filter.init(dirpath, useDenoise)
try:
filter.init(dirpath, useDenoise)
except Exception as e:
print("An error occured during filtering. See the line below for more detail:")
print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
tlm_log.append("An error occured during filtering. See the line below for more detail:")
tlm_log.append(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
if not bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Turn on verbose mode to get more detail.")
#Encoding
if sceneProperties.tlm_encoding_use and scene.TLM_EngineProperties.tlm_bake_mode != "Background":
@ -360,7 +421,9 @@ def begin_build():
if sceneProperties.tlm_format == "EXR":
tlm_log.append("EXR Format")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("EXR Format")
ren = bpy.context.scene.render
@ -390,7 +453,9 @@ def begin_build():
if sceneProperties.tlm_encoding_mode_a == "RGBM":
tlm_log.append("ENCODING RGBM")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("ENCODING RGBM")
dirfiles = [f for f in listdir(dirpath) if isfile(join(dirpath, f))]
@ -410,13 +475,16 @@ def begin_build():
img = bpy.data.images.load(os.path.join(dirpath, file), check_existing=False)
tlm_log.append("Encoding:" + str(file))
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Encoding:" + str(file))
encoding.encodeImageRGBMCPU(img, sceneProperties.tlm_encoding_range, dirpath, 0)
if sceneProperties.tlm_encoding_mode_a == "RGBD":
tlm_log.append("ENCODING RGBD")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("ENCODING RGBD")
dirfiles = [f for f in listdir(dirpath) if isfile(join(dirpath, f))]
@ -437,12 +505,15 @@ def begin_build():
img = bpy.data.images.load(os.path.join(dirpath, file), check_existing=False)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
tlm_log.append("Encoding:" + str(file))
print("Encoding:" + str(file))
encoding.encodeImageRGBDCPU(img, sceneProperties.tlm_encoding_range, dirpath, 0)
if sceneProperties.tlm_encoding_mode_a == "SDR":
tlm_log.append("EXR Format")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("EXR Format")
ren = bpy.context.scene.render
@ -476,7 +547,9 @@ def begin_build():
if sceneProperties.tlm_format == "EXR":
tlm_log.append("EXR Format")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("EXR Format")
ren = bpy.context.scene.render
@ -518,6 +591,7 @@ def begin_build():
end = "_filtered"
#CHECK FOR ATLAS MAPS!
for file in dirfiles:
if file.endswith(end + ".hdr"):
@ -525,9 +599,23 @@ def begin_build():
encoding.encodeLogLuvGPU(img, dirpath, 0)
if sceneProperties.tlm_split_premultiplied:
image_name = img.name
if image_name[-4:] == '.exr' or image_name[-4:] == '.hdr':
image_name = image_name[:-4]
image_name = image_name + '_encoded.png'
print("SPLIT PREMULTIPLIED: " + image_name)
encoding.splitLogLuvAlpha(os.path.join(dirpath, image_name), dirpath, 0)
if sceneProperties.tlm_encoding_mode_b == "RGBM":
tlm_log.append("ENCODING RGBM")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("ENCODING RGBM")
dirfiles = [f for f in listdir(dirpath) if isfile(join(dirpath, f))]
@ -606,19 +694,50 @@ def begin_build():
manage_build()
def manage_build(background_pass=False):
def manage_build(background_pass=False, load_atlas=0):
print("Managing build")
if load_atlas:
print("Managing in load atlas mode")
scene = bpy.context.scene
sceneProperties = scene.TLM_SceneProperties
if sceneProperties.tlm_lightmap_engine == "Cycles":
if background_pass:
nodes.apply_lightmaps()
print("In background pass")
nodes.apply_materials() #From here the name is changed...
try:
nodes.apply_lightmaps()
except Exception as e:
print("An error occured during lightmap application. See the line below for more detail:")
print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
tlm_log.append("An error occured during lightmap application. See the line below for more detail:")
tlm_log.append(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
if not bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Turn on verbose mode to get more detail.")
try:
nodes.apply_materials(load_atlas) #From here the name is changed...
except Exception as e:
print("An error occured during material application. See the line below for more detail:")
print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
tlm_log.append("An error occured during material application. See the line below for more detail:")
tlm_log.append(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
if not bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Turn on verbose mode to get more detail.")
end = "_baked"
@ -693,6 +812,111 @@ def manage_build(background_pass=False):
supersampling_scale = 1
pack.postpack()
#We need to also make sure out postpacked atlases gets split w. premultiplied
#CHECK FOR ATLAS MAPS!
if bpy.context.scene.TLM_SceneProperties.tlm_encoding_use and bpy.context.scene.TLM_SceneProperties.tlm_encoding_device == "GPU":
if bpy.context.scene.TLM_SceneProperties.tlm_split_premultiplied and bpy.context.scene.TLM_SceneProperties.tlm_encoding_use and bpy.context.scene.TLM_SceneProperties.tlm_encoding_device == "GPU" and bpy.context.scene.TLM_SceneProperties.tlm_encoding_mode_b == "LogLuv":
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), scene.TLM_EngineProperties.tlm_lightmap_savedir)
dirfiles = [f for f in listdir(dirpath) if isfile(join(dirpath, f))]
for atlas in bpy.context.scene.TLM_PostAtlasList:
for file in dirfiles:
if file.startswith(atlas.name):
print("TODO: SPLIT LOGLUV FOR: " + str(file))
encoding.splitLogLuvAlpha(os.path.join(dirpath, file), dirpath, 0)
#Need to update file list for some reason?
dirfiles = [f for f in listdir(dirpath) if isfile(join(dirpath, f))]
for atlas in bpy.context.scene.TLM_PostAtlasList:
#FIND SOME WAY TO FIND THE RIGTH FILE! TOO TIRED NOW!
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_postpack_object:
if obj.TLM_ObjectProperties.tlm_postatlas_pointer == atlas.name:
for slot in obj.material_slots:
mat = slot.material
node_tree = mat.node_tree
foundBakedNode = False
#for file in dirfiles:
# if file.startswith(atlas.name):
# if file.endswith("XYZ"):
#Find nodes
for node in node_tree.nodes:
if node.name == "TLM_Lightmap":
print("Found the main lightmap node: LOGLUV")
for file in dirfiles:
if file.startswith(atlas.name) and file.endswith("XYZ.png"):
print("Found an atlas file: " + str(file))
node.image.filepath_raw = os.path.join(dirpath, file)
print("CHANGED LIGHTMAP MAIN INTO XYZ: " + str(file))
if node.name == "TLM_Lightmap_Extra":
print("Found the main lightmap node: LOGLUV")
for file in dirfiles:
if file.startswith(atlas.name) and file.endswith("W.png"):
print("Found an atlas file: " + str(file))
node.image.filepath_raw = os.path.join(dirpath, file)
print("CHANGED LIGHTMAP MAIN INTO W: " + str(file))
#print("Found the extra lightmap node: LOGLUV")
# if node.image.filepath_raw.startswith(atlas.name):
# if node.image.filepath_raw.endswith("W.png"):
# print("ALREADY W: " + str(node.image.filepath_raw))
# else:
# for file in dirfiles:
# if file.startswith(atlas.name):
# if file.endswith("W.png"):
# node.image.filepath_raw = os.path.join(dirpath, file)
# print("CHANGED LIGHTMAP MAIN INTO W: " + str(file))
#for file in dirfiles:
# if file.endswith(end + ".hdr"):
#for atlas in bpy.context.scene.TLM_PostAtlasList:
#print("TODO: SPLIT LOGLUV FOR: " + str(atlas.name) + "..file?")
#CHECK FOR ATLAS MAPS!
#dirfiles = [f for f in listdir(dirpath) if isfile(join(dirpath, f))]
# for file in dirfiles:
# if file.endswith(end + ".hdr"):
# img = bpy.data.images.load(os.path.join(dirpath, file), check_existing=False)
# encoding.encodeLogLuvGPU(img, dirpath, 0)
# if sceneProperties.tlm_split_premultiplied:
# image_name = img.name
# if image_name[-4:] == '.exr' or image_name[-4:] == '.hdr':
# image_name = image_name[:-4]
# image_name = image_name + '_encoded.png'
# print("SPLIT PREMULTIPLIED: " + image_name)
# encoding.splitLogLuvAlpha(os.path.join(dirpath, image_name), dirpath, 0)
for image in bpy.data.images:
if image.users < 1:
@ -815,7 +1039,9 @@ def manage_build(background_pass=False):
print("Second AO pass complete")
total_time = sec_to_hours((time() - start_time))
tlm_log.append(total_time)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(total_time)
bpy.context.scene["TLM_Buildstat"] = total_time
@ -835,6 +1061,7 @@ def manage_build(background_pass=False):
else:
total_time = sec_to_hours((time() - start_time))
tlm_log.append(total_time)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(total_time)
@ -842,6 +1069,8 @@ def manage_build(background_pass=False):
reset_settings(previous_settings["settings"])
tlm_log.append("Lightmap building finished")
tlm_log.append("--------------------------")
print("Lightmap building finished")
if sceneProperties.tlm_lightmap_engine == "LuxCoreRender":
@ -855,7 +1084,7 @@ def manage_build(background_pass=False):
if bpy.context.scene.TLM_EngineProperties.tlm_bake_mode == "Background":
pass
if not background_pass and bpy.context.scene.TLM_EngineProperties.tlm_lighting_mode != "combinedao":
if not background_pass and scene.TLM_EngineProperties.tlm_bake_mode != "Background" and bpy.context.scene.TLM_EngineProperties.tlm_lighting_mode != "combinedao":
#pass
setGui(0)
@ -879,6 +1108,10 @@ def manage_build(background_pass=False):
sound = aud.Sound.file(sound_path)
device.play(sound)
if logging:
print("Log file output:")
tlm_log.dumpLog()
if bpy.app.background:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
@ -945,6 +1178,8 @@ def naming_check():
obj.name = obj.name.replace("æ","ae")
if "å" in obj.name:
obj.name = obj.name.replace("å","aa")
if "/" in obj.name:
obj.name = obj.name.replace("/",".")
for slot in obj.material_slots:
if "_" in slot.material.name:
@ -961,6 +1196,8 @@ def naming_check():
slot.material.name = slot.material.name.replace("æ","ae")
if "å" in slot.material.name:
slot.material.name = slot.material.name.replace("å","aa")
if "/" in slot.material.name:
slot.material.name = slot.material.name.replace("/",".")
def opencv_check():
@ -999,6 +1236,11 @@ def check_denoiser():
if platform.system() == "Windows":
if not scene.TLM_OIDNEngineProperties.tlm_oidn_path.endswith(".exe"):
return 1
else:
if os.path.isfile(bpy.path.abspath(scene.TLM_OIDNEngineProperties.tlm_oidn_path)):
return 0
else:
return 1
else:
return 0
@ -1034,7 +1276,17 @@ def setMode():
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.mode_set(mode='OBJECT')
hidden = False
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
if not hidden:
bpy.ops.object.mode_set(mode='OBJECT')
#TODO Make some checks that returns to previous selection
@ -1092,5 +1344,4 @@ def checkAtlasSize():
if overflow == True:
return True
else:
return False
return False

View File

@ -4,6 +4,9 @@ from time import time, sleep
def bake(plus_pass=0):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Initializing lightmap baking.")
for obj in bpy.context.scene.objects:
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(False)
@ -13,15 +16,74 @@ def bake(plus_pass=0):
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
iterNum = iterNum + 1
hidden = False
#We check if the object is hidden
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
#We check if the object's collection is hidden
collections = obj.users_collection
for collection in collections:
if collection.hide_viewport:
hidden = True
if collection.hide_render:
hidden = True
try:
if collection.name in bpy.context.scene.view_layers[0].layer_collection.children:
if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport:
hidden = True
except:
print("Error: Could not find collection: " + collection.name)
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use and not hidden:
iterNum = iterNum + 1
if iterNum > 1:
iterNum = iterNum - 1
for obj in bpy.context.scene.objects:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Checking visibility status for object and collections: " + obj.name)
hidden = False
#We check if the object is hidden
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
#We check if the object's collection is hidden
collections = obj.users_collection
for collection in collections:
if collection.hide_viewport:
hidden = True
if collection.hide_render:
hidden = True
try:
if collection.name in bpy.context.scene.view_layers[0].layer_collection.children:
if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport:
hidden = True
except:
print("Error: Could not find collection: " + collection.name)
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use and not hidden:
scene = bpy.context.scene
@ -52,13 +114,16 @@ def bake(plus_pass=0):
#print("Remaining: " + str(remaining))
if scene.TLM_EngineProperties.tlm_target == "vertex":
scene.render.bake_target = "VERTEX_COLORS"
scene.render.bake.target = "VERTEX_COLORS"
if scene.TLM_EngineProperties.tlm_lighting_mode == "combined":
print("Baking combined: Direct + Indirect")
bpy.ops.object.bake(type="DIFFUSE", pass_filter={"DIRECT","INDIRECT"}, margin=scene.TLM_EngineProperties.tlm_dilation_margin, use_clear=False)
elif scene.TLM_EngineProperties.tlm_lighting_mode == "indirect":
print("Baking combined: Indirect")
bpy.ops.object.bake(type="DIFFUSE", pass_filter={"INDIRECT"}, margin=scene.TLM_EngineProperties.tlm_dilation_margin, use_clear=False)
elif scene.TLM_EngineProperties.tlm_lighting_mode == "ao":
print("Baking combined: AO")
bpy.ops.object.bake(type="AO", margin=scene.TLM_EngineProperties.tlm_dilation_margin, use_clear=False)
elif scene.TLM_EngineProperties.tlm_lighting_mode == "combinedao":
@ -67,12 +132,35 @@ def bake(plus_pass=0):
elif bpy.app.driver_namespace["tlm_plus_mode"] == 2:
bpy.ops.object.bake(type="AO", margin=scene.TLM_EngineProperties.tlm_dilation_margin, use_clear=False)
elif scene.TLM_EngineProperties.tlm_lighting_mode == "indirectao":
print("IndirAO")
if bpy.app.driver_namespace["tlm_plus_mode"] == 1:
bpy.ops.object.bake(type="DIFFUSE", pass_filter={"DIRECT","INDIRECT"}, margin=scene.TLM_EngineProperties.tlm_dilation_margin, use_clear=False)
elif bpy.app.driver_namespace["tlm_plus_mode"] == 2:
bpy.ops.object.bake(type="AO", margin=scene.TLM_EngineProperties.tlm_dilation_margin, use_clear=False)
elif scene.TLM_EngineProperties.tlm_lighting_mode == "complete":
bpy.ops.object.bake(type="COMBINED", margin=scene.TLM_EngineProperties.tlm_dilation_margin, use_clear=False)
else:
bpy.ops.object.bake(type="DIFFUSE", pass_filter={"DIRECT","INDIRECT"}, margin=scene.TLM_EngineProperties.tlm_dilation_margin, use_clear=False)
#Save image between
if scene.TLM_SceneProperties.tlm_save_preprocess_lightmaps:
for image in bpy.data.images:
if image.name.endswith("_baked"):
saveDir = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
bakemap_path = os.path.join(saveDir, image.name)
filepath_ext = ".hdr"
image.filepath_raw = bakemap_path + filepath_ext
image.file_format = "HDR"
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Saving to: " + image.filepath_raw)
image.save()
bpy.ops.object.select_all(action='DESELECT')
currentIterNum = currentIterNum + 1
@ -86,4 +174,4 @@ def bake(plus_pass=0):
image.file_format = "HDR"
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Saving to: " + image.filepath_raw)
image.save()
image.save()

View File

@ -4,271 +4,447 @@ def apply_lightmaps():
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
for slot in obj.material_slots:
mat = slot.material
node_tree = mat.node_tree
nodes = mat.node_tree.nodes
scene = bpy.context.scene
hidden = False
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), scene.TLM_EngineProperties.tlm_lightmap_savedir)
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
#Find nodes
for node in nodes:
if node.name == "Baked Image":
extension = ".hdr"
postfix = "_baked"
if scene.TLM_SceneProperties.tlm_denoise_use:
postfix = "_denoised"
if scene.TLM_SceneProperties.tlm_filtering_use:
postfix = "_filtered"
node.image.source = "FILE"
image_name = obj.name + postfix + extension #TODO FIX EXTENSION
node.image.filepath_raw = os.path.join(dirpath, image_name)
def apply_materials():
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Applying materials")
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
uv_layers = obj.data.uv_layers
uv_layers.active_index = 0
scene = bpy.context.scene
decoding = False
#Sort name
for slot in obj.material_slots:
mat = slot.material
if mat.name.endswith('_temp'):
old = slot.material
slot.material = bpy.data.materials[old.name.split('_' + obj.name)[0]]
if(scene.TLM_SceneProperties.tlm_decoder_setup):
tlm_rgbm = bpy.data.node_groups.get('RGBM Decode')
tlm_rgbd = bpy.data.node_groups.get('RGBD Decode')
tlm_logluv = bpy.data.node_groups.get('LogLuv Decode')
if tlm_rgbm == None:
load_library('RGBM Decode')
if tlm_rgbd == None:
load_library('RGBD Decode')
if tlm_logluv == None:
load_library('LogLuv Decode')
if(scene.TLM_EngineProperties.tlm_exposure_multiplier > 0):
tlm_exposure = bpy.data.node_groups.get("Exposure")
if tlm_exposure == None:
load_library("Exposure")
#Apply materials
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(obj.name)
for slot in obj.material_slots:
mat = slot.material
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(slot.material)
if not mat.TLM_ignore:
if not hidden:
for slot in obj.material_slots:
mat = slot.material
node_tree = mat.node_tree
nodes = mat.node_tree.nodes
foundBakedNode = False
scene = bpy.context.scene
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), scene.TLM_EngineProperties.tlm_lightmap_savedir)
#Find nodes
for node in nodes:
if node.name == "Baked Image":
lightmapNode = node
lightmapNode.location = -1200, 300
lightmapNode.name = "TLM_Lightmap"
foundBakedNode = True
img_name = obj.name + '_baked'
if not foundBakedNode:
lightmapNode = node_tree.nodes.new(type="ShaderNodeTexImage")
lightmapNode.location = -1200, 300
lightmapNode.name = "TLM_Lightmap"
lightmapNode.interpolation = bpy.context.scene.TLM_SceneProperties.tlm_texture_interpolation
lightmapNode.extension = bpy.context.scene.TLM_SceneProperties.tlm_texture_extrapolation
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Finding node source for material: " + mat.name + " @ " + obj.name)
if (obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA" and obj.TLM_ObjectProperties.tlm_atlas_pointer != ""):
lightmapNode.image = bpy.data.images[obj.TLM_ObjectProperties.tlm_atlas_pointer + "_baked"]
else:
lightmapNode.image = bpy.data.images[img_name]
extension = ".hdr"
#Find output node
outputNode = nodes[0]
if(outputNode.type != "OUTPUT_MATERIAL"):
for node in node_tree.nodes:
if node.type == "OUTPUT_MATERIAL":
outputNode = node
break
postfix = "_baked"
#Find mainnode
mainNode = outputNode.inputs[0].links[0].from_node
if scene.TLM_SceneProperties.tlm_denoise_use:
postfix = "_denoised"
if scene.TLM_SceneProperties.tlm_filtering_use:
postfix = "_filtered"
#Add all nodes first
#Add lightmap multipliction texture
mixNode = node_tree.nodes.new(type="ShaderNodeMixRGB")
mixNode.name = "Lightmap_Multiplication"
mixNode.location = -800, 300
if scene.TLM_EngineProperties.tlm_lighting_mode == "indirect" or scene.TLM_EngineProperties.tlm_lighting_mode == "indirectAO":
mixNode.blend_type = 'ADD'
else:
mixNode.blend_type = 'MULTIPLY'
if scene.TLM_EngineProperties.tlm_lighting_mode == "complete":
mixNode.inputs[0].default_value = 0.0
else:
mixNode.inputs[0].default_value = 1.0
if node.image:
node.image.source = "FILE"
UVLightmap = node_tree.nodes.new(type="ShaderNodeUVMap")
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
print("Atlas object image")
image_name = obj.TLM_ObjectProperties.tlm_atlas_pointer + postfix + extension #TODO FIX EXTENSION
elif obj.TLM_ObjectProperties.tlm_postpack_object:
print("Atlas object image (postpack)")
image_name = obj.TLM_ObjectProperties.tlm_postatlas_pointer + postfix + extension #TODO FIX EXTENSION
else:
print("Baked object image")
image_name = obj.name + postfix + extension #TODO FIX EXTENSION
node.image.filepath_raw = os.path.join(dirpath, image_name)
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel
else:
uv_channel = "UVMap_Lightmap"
UVLightmap.uv_map = uv_channel
UVLightmap.name = "Lightmap_UV"
UVLightmap.location = -1500, 300
if(scene.TLM_SceneProperties.tlm_decoder_setup):
if scene.TLM_SceneProperties.tlm_encoding_device == "CPU":
if scene.TLM_SceneProperties.tlm_encoding_mode_a == 'RGBM':
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["RGBM Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_RGBM_Decode"
decoding = True
if scene.TLM_SceneProperties.tlm_encoding_mode_b == "RGBD":
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["RGBD Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_RGBD_Decode"
decoding = True
else:
if scene.TLM_SceneProperties.tlm_encoding_mode_b == 'RGBM':
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["RGBM Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_RGBM_Decode"
decoding = True
if scene.TLM_SceneProperties.tlm_encoding_mode_b == "RGBD":
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["RGBD Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_RGBD_Decode"
decoding = True
if scene.TLM_SceneProperties.tlm_encoding_mode_b == "LogLuv":
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["LogLuv Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_LogLuv_Decode"
decoding = True
if(scene.TLM_EngineProperties.tlm_exposure_multiplier > 0):
ExposureNode = node_tree.nodes.new(type="ShaderNodeGroup")
ExposureNode.node_tree = bpy.data.node_groups["Exposure"]
ExposureNode.inputs[1].default_value = scene.TLM_EngineProperties.tlm_exposure_multiplier
ExposureNode.location = -500, 300
ExposureNode.name = "Lightmap_Exposure"
#Add Basecolor node
if len(mainNode.inputs[0].links) == 0:
baseColorValue = mainNode.inputs[0].default_value
baseColorNode = node_tree.nodes.new(type="ShaderNodeRGB")
baseColorNode.outputs[0].default_value = baseColorValue
baseColorNode.location = ((mainNode.location[0] - 1100, mainNode.location[1] - 300))
baseColorNode.name = "Lightmap_BasecolorNode_A"
else:
baseColorNode = mainNode.inputs[0].links[0].from_node
baseColorNode.name = "LM_P"
#Linking
if decoding and scene.TLM_SceneProperties.tlm_encoding_use:
if(scene.TLM_EngineProperties.tlm_exposure_multiplier > 0):
mat.node_tree.links.new(lightmapNode.outputs[0], DecodeNode.inputs[0]) #Connect lightmap node to mixnode
mat.node_tree.links.new(lightmapNode.outputs[1], DecodeNode.inputs[1]) #Connect lightmap node to mixnode
mat.node_tree.links.new(DecodeNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
mat.node_tree.links.new(ExposureNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
else:
mat.node_tree.links.new(lightmapNode.outputs[0], DecodeNode.inputs[0]) #Connect lightmap node to mixnode
mat.node_tree.links.new(lightmapNode.outputs[1], DecodeNode.inputs[1]) #Connect lightmap node to mixnode
mat.node_tree.links.new(DecodeNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
mat.node_tree.links.new(baseColorNode.outputs[0], mixNode.inputs[2]) #Connect basecolor to pbr node
mat.node_tree.links.new(mixNode.outputs[0], mainNode.inputs[0]) #Connect mixnode to pbr node
mat.node_tree.links.new(UVLightmap.outputs[0], lightmapNode.inputs[0]) #Connect uvnode to lightmapnode
else:
if(scene.TLM_EngineProperties.tlm_exposure_multiplier > 0):
mat.node_tree.links.new(lightmapNode.outputs[0], ExposureNode.inputs[0]) #Connect lightmap node to mixnode
mat.node_tree.links.new(ExposureNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
else:
mat.node_tree.links.new(lightmapNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
mat.node_tree.links.new(baseColorNode.outputs[0], mixNode.inputs[2]) #Connect basecolor to pbr node
mat.node_tree.links.new(mixNode.outputs[0], mainNode.inputs[0]) #Connect mixnode to pbr node
mat.node_tree.links.new(UVLightmap.outputs[0], lightmapNode.inputs[0]) #Connect uvnode to lightmapnode
#If skip metallic
if scene.TLM_SceneProperties.tlm_metallic_clamp == "skip":
if mainNode.inputs[4].default_value > 0.1: #DELIMITER
moutput = mainNode.inputs[0].links[0].from_node
mat.node_tree.links.remove(moutput.outputs[0].links[0])
def exchangeLightmapsToPostfix(ext_postfix, new_postfix, formatHDR=".hdr"):
def apply_materials(load_atlas=0):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(ext_postfix, new_postfix, formatHDR)
print("Applying materials")
if load_atlas:
print("- In load Atlas mode")
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
for slot in obj.material_slots:
mat = slot.material
node_tree = mat.node_tree
nodes = mat.node_tree.nodes
for node in nodes:
if node.name == "Baked Image" or node.name == "TLM_Lightmap":
img_name = node.image.filepath_raw
cutLen = len(ext_postfix + formatHDR)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Len:" + str(len(ext_postfix + formatHDR)) + "|" + ext_postfix + ".." + formatHDR)
hidden = False
#Simple way to sort out objects with multiple materials
if formatHDR == ".hdr" or formatHDR == ".exr":
if not node.image.filepath_raw.endswith(new_postfix + formatHDR):
node.image.filepath_raw = img_name[:-cutLen] + new_postfix + formatHDR
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
if not hidden:
uv_layers = obj.data.uv_layers
uv_layers.active_index = 0
scene = bpy.context.scene
decoding = False
#Sort name
for slot in obj.material_slots:
mat = slot.material
if mat.name.endswith('_temp'):
old = slot.material
slot.material = bpy.data.materials[old.name.split('_' + obj.name)[0]]
if(scene.TLM_SceneProperties.tlm_decoder_setup):
tlm_rgbm = bpy.data.node_groups.get('RGBM Decode')
tlm_rgbd = bpy.data.node_groups.get('RGBD Decode')
tlm_logluv = bpy.data.node_groups.get('LogLuv Decode')
if tlm_rgbm == None:
load_library('RGBM Decode')
if tlm_rgbd == None:
load_library('RGBD Decode')
if tlm_logluv == None:
load_library('LogLuv Decode')
if(scene.TLM_EngineProperties.tlm_exposure_multiplier > 0):
tlm_exposure = bpy.data.node_groups.get("Exposure")
if tlm_exposure == None:
load_library("Exposure")
#Apply materials
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(obj.name)
for slot in obj.material_slots:
mat = slot.material
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(slot.material)
if not mat.TLM_ignore:
node_tree = mat.node_tree
nodes = mat.node_tree.nodes
foundBakedNode = False
#Find nodes
for node in nodes:
if node.name == "Baked Image":
lightmapNode = node
lightmapNode.location = -1200, 300
lightmapNode.name = "TLM_Lightmap"
foundBakedNode = True
# if load_atlas:
# print("Load Atlas for: " + obj.name)
# img_name = obj.TLM_ObjectProperties.tlm_atlas_pointer + '_baked'
# print("Src: " + img_name)
# else:
# img_name = obj.name + '_baked'
img_name = obj.name + '_baked'
if not foundBakedNode:
if scene.TLM_EngineProperties.tlm_target == "vertex":
lightmapNode = node_tree.nodes.new(type="ShaderNodeVertexColor")
lightmapNode.location = -1200, 300
lightmapNode.name = "TLM_Lightmap"
else:
lightmapNode = node_tree.nodes.new(type="ShaderNodeTexImage")
lightmapNode.location = -1200, 300
lightmapNode.name = "TLM_Lightmap"
lightmapNode.interpolation = bpy.context.scene.TLM_SceneProperties.tlm_texture_interpolation
lightmapNode.extension = bpy.context.scene.TLM_SceneProperties.tlm_texture_extrapolation
if (obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA" and obj.TLM_ObjectProperties.tlm_atlas_pointer != ""):
lightmapNode.image = bpy.data.images[obj.TLM_ObjectProperties.tlm_atlas_pointer + "_baked"]
else:
lightmapNode.image = bpy.data.images[img_name]
#Find output node
outputNode = nodes[0]
if(outputNode.type != "OUTPUT_MATERIAL"):
for node in node_tree.nodes:
if node.type == "OUTPUT_MATERIAL":
outputNode = node
break
#Find mainnode
mainNode = outputNode.inputs[0].links[0].from_node
if (mainNode.type == "MIX_SHADER"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Mix shader found")
#TODO SHIFT BETWEEN from node input 1 or 2 based on which type
mainNode = outputNode.inputs[0].links[0].from_node.inputs[1].links[0].from_node
if (mainNode.type == "ADD_SHADER"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Mix shader found")
mainNode = outputNode.inputs[0].links[0].from_node.inputs[0].links[0].from_node
if (mainNode.type == "ShaderNodeMixRGB"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Mix RGB shader found")
mainNode = outputNode.inputs[0].links[0].from_node.inputs[0].links[0].from_node
#Add all nodes first
#Add lightmap multipliction texture
mixNode = node_tree.nodes.new(type="ShaderNodeMixRGB")
mixNode.name = "Lightmap_Multiplication"
mixNode.location = -800, 300
if scene.TLM_EngineProperties.tlm_lighting_mode == "indirect" or scene.TLM_EngineProperties.tlm_lighting_mode == "indirectAO":
mixNode.blend_type = 'MULTIPLY'
else:
cutLen = len(ext_postfix + ".hdr")
if not node.image.filepath_raw.endswith(new_postfix + formatHDR):
node.image.filepath_raw = img_name[:-cutLen] + new_postfix + formatHDR
mixNode.blend_type = 'MULTIPLY'
if scene.TLM_EngineProperties.tlm_lighting_mode == "complete":
mixNode.inputs[0].default_value = 0.0
else:
mixNode.inputs[0].default_value = 1.0
UVLightmap = node_tree.nodes.new(type="ShaderNodeUVMap")
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel
else:
uv_channel = "UVMap_Lightmap"
UVLightmap.uv_map = uv_channel
UVLightmap.name = "Lightmap_UV"
UVLightmap.location = -1500, 300
if(scene.TLM_SceneProperties.tlm_decoder_setup):
if scene.TLM_SceneProperties.tlm_encoding_device == "CPU":
if scene.TLM_SceneProperties.tlm_encoding_mode_a == 'RGBM':
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["RGBM Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_RGBM_Decode"
decoding = True
if scene.TLM_SceneProperties.tlm_encoding_mode_b == "RGBD":
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["RGBD Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_RGBD_Decode"
decoding = True
else:
if scene.TLM_SceneProperties.tlm_encoding_mode_b == 'RGBM':
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["RGBM Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_RGBM_Decode"
decoding = True
if scene.TLM_SceneProperties.tlm_encoding_mode_b == "RGBD":
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["RGBD Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_RGBD_Decode"
decoding = True
if scene.TLM_SceneProperties.tlm_encoding_mode_b == "LogLuv":
DecodeNode = node_tree.nodes.new(type="ShaderNodeGroup")
DecodeNode.node_tree = bpy.data.node_groups["LogLuv Decode"]
DecodeNode.location = -400, 300
DecodeNode.name = "Lightmap_LogLuv_Decode"
decoding = True
if scene.TLM_SceneProperties.tlm_split_premultiplied:
lightmapNodeExtra = node_tree.nodes.new(type="ShaderNodeTexImage")
lightmapNodeExtra.location = -1200, 800
lightmapNodeExtra.name = "TLM_Lightmap_Extra"
lightmapNodeExtra.interpolation = bpy.context.scene.TLM_SceneProperties.tlm_texture_interpolation
lightmapNodeExtra.extension = bpy.context.scene.TLM_SceneProperties.tlm_texture_extrapolation
lightmapNodeExtra.image = lightmapNode.image
# #IF OBJ IS USING ATLAS?
# if (obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA" and obj.TLM_ObjectProperties.tlm_atlas_pointer != ""):
# #lightmapNode.image = bpy.data.images[obj.TLM_ObjectProperties.tlm_atlas_pointer + "_baked"]
# #print("OBS! OBJ IS USING ATLAS, RESULT WILL BE WRONG!")
# #bpy.app.driver_namespace["logman"].append("OBS! OBJ IS USING ATLAS, RESULT WILL BE WRONG!")
# pass
# if (obj.TLM_ObjectProperties.tlm_postpack_object and obj.TLM_ObjectProperties.tlm_postatlas_pointer != ""):
# #print("OBS! OBJ IS USING ATLAS, RESULT WILL BE WRONG!")
# #bpy.app.driver_namespace["logman"].append("OBS! OBJ IS USING ATLAS, RESULT WILL BE WRONG!")
# print()
# lightmapNodeExtra.image = lightmapNode.image
#lightmapPath = lightmapNode.image.filepath_raw
#print("PREM: " + lightmapPath)
if(scene.TLM_EngineProperties.tlm_exposure_multiplier > 0):
ExposureNode = node_tree.nodes.new(type="ShaderNodeGroup")
ExposureNode.node_tree = bpy.data.node_groups["Exposure"]
ExposureNode.inputs[1].default_value = scene.TLM_EngineProperties.tlm_exposure_multiplier
ExposureNode.location = -500, 300
ExposureNode.name = "Lightmap_Exposure"
#Add Basecolor node
if len(mainNode.inputs[0].links) == 0:
baseColorValue = mainNode.inputs[0].default_value
baseColorNode = node_tree.nodes.new(type="ShaderNodeRGB")
baseColorNode.outputs[0].default_value = baseColorValue
baseColorNode.location = ((mainNode.location[0] - 1100, mainNode.location[1] - 300))
baseColorNode.name = "Lightmap_BasecolorNode_A"
else:
baseColorNode = mainNode.inputs[0].links[0].from_node
baseColorNode.name = "LM_P"
#Linking
if decoding and scene.TLM_SceneProperties.tlm_encoding_use:
if(scene.TLM_EngineProperties.tlm_exposure_multiplier > 0):
mat.node_tree.links.new(lightmapNode.outputs[0], DecodeNode.inputs[0]) #Connect lightmap node to decodenode
if scene.TLM_SceneProperties.tlm_split_premultiplied:
mat.node_tree.links.new(lightmapNodeExtra.outputs[0], DecodeNode.inputs[1]) #Connect lightmap node to decodenode
else:
mat.node_tree.links.new(lightmapNode.outputs[1], DecodeNode.inputs[1]) #Connect lightmap node to decodenode
mat.node_tree.links.new(DecodeNode.outputs[0], mixNode.inputs[1]) #Connect decode node to mixnode
mat.node_tree.links.new(ExposureNode.outputs[0], mixNode.inputs[1]) #Connect exposure node to mixnode
else:
mat.node_tree.links.new(lightmapNode.outputs[0], DecodeNode.inputs[0]) #Connect lightmap node to decodenode
if scene.TLM_SceneProperties.tlm_split_premultiplied:
mat.node_tree.links.new(lightmapNodeExtra.outputs[0], DecodeNode.inputs[1]) #Connect lightmap node to decodenode
else:
mat.node_tree.links.new(lightmapNode.outputs[1], DecodeNode.inputs[1]) #Connect lightmap node to decodenode
mat.node_tree.links.new(DecodeNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
mat.node_tree.links.new(baseColorNode.outputs[0], mixNode.inputs[2]) #Connect basecolor to pbr node
mat.node_tree.links.new(mixNode.outputs[0], mainNode.inputs[0]) #Connect mixnode to pbr node
if not scene.TLM_EngineProperties.tlm_target == "vertex":
mat.node_tree.links.new(UVLightmap.outputs[0], lightmapNode.inputs[0]) #Connect uvnode to lightmapnode
if scene.TLM_SceneProperties.tlm_split_premultiplied:
mat.node_tree.links.new(UVLightmap.outputs[0], lightmapNodeExtra.inputs[0]) #Connect uvnode to lightmapnode
else:
if(scene.TLM_EngineProperties.tlm_exposure_multiplier > 0):
mat.node_tree.links.new(lightmapNode.outputs[0], ExposureNode.inputs[0]) #Connect lightmap node to mixnode
mat.node_tree.links.new(ExposureNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
else:
mat.node_tree.links.new(lightmapNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
mat.node_tree.links.new(baseColorNode.outputs[0], mixNode.inputs[2]) #Connect basecolor to pbr node
mat.node_tree.links.new(mixNode.outputs[0], mainNode.inputs[0]) #Connect mixnode to pbr node
if not scene.TLM_EngineProperties.tlm_target == "vertex":
mat.node_tree.links.new(UVLightmap.outputs[0], lightmapNode.inputs[0]) #Connect uvnode to lightmapnode
#If skip metallic
if scene.TLM_SceneProperties.tlm_metallic_clamp == "skip":
if mainNode.inputs[4].default_value > 0.1: #DELIMITER
moutput = mainNode.inputs[0].links[0].from_node
mat.node_tree.links.remove(moutput.outputs[0].links[0])
def exchangeLightmapsToPostfix(ext_postfix, new_postfix, formatHDR=".hdr"):
if not bpy.context.scene.TLM_EngineProperties.tlm_target == "vertex":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(ext_postfix, new_postfix, formatHDR)
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
#Here
#If the object is part of atlas
print("CHECKING FOR REPART")
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA": #TODO, ALSO CONFIGURE FOR POSTATLAS
if bpy.context.scene.TLM_AtlasList[obj.TLM_ObjectProperties.tlm_atlas_pointer].tlm_atlas_merge_samemat:
#For each material we check if it ends with a number
for slot in obj.material_slots:
part = slot.name.rpartition('.')
if part[2].isnumeric() and part[0] in bpy.data.materials:
print("Material for obj: " + obj.name + " was numeric, and the material: " + part[0] + " was found.")
slot.material = bpy.data.materials.get(part[0])
# for slot in obj.material_slots:
# mat = slot.material
# node_tree = mat.node_tree
# nodes = mat.node_tree.nodes
try:
hidden = False
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
if not hidden:
for slot in obj.material_slots:
mat = slot.material
node_tree = mat.node_tree
nodes = mat.node_tree.nodes
for node in nodes:
if node.name == "Baked Image" or node.name == "TLM_Lightmap":
img_name = node.image.filepath_raw
cutLen = len(ext_postfix + formatHDR)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Len:" + str(len(ext_postfix + formatHDR)) + "|" + ext_postfix + ".." + formatHDR)
#Simple way to sort out objects with multiple materials
if formatHDR == ".hdr" or formatHDR == ".exr":
if not node.image.filepath_raw.endswith(new_postfix + formatHDR):
print("Node1: " + node.image.filepath_raw + " => " + img_name[:-cutLen] + new_postfix + formatHDR)
node.image.filepath_raw = img_name[:-cutLen] + new_postfix + formatHDR
else:
cutLen = len(ext_postfix + ".hdr")
if not node.image.filepath_raw.endswith(new_postfix + formatHDR):
if not node.image.filepath_raw.endswith("_XYZ.png"):
print("Node2: " + node.image.filepath_raw + " => " + img_name[:-cutLen] + new_postfix + formatHDR)
node.image.filepath_raw = img_name[:-cutLen] + new_postfix + formatHDR
for node in nodes:
if bpy.context.scene.TLM_SceneProperties.tlm_encoding_use and bpy.context.scene.TLM_SceneProperties.tlm_encoding_mode_b == "LogLuv":
if bpy.context.scene.TLM_SceneProperties.tlm_split_premultiplied:
if node.name == "TLM_Lightmap":
img_name = node.image.filepath_raw
print("PREM Main: " + img_name)
if node.image.filepath_raw.endswith("_encoded.png"):
print(node.image.filepath_raw + " => " + node.image.filepath_raw[:-4] + "_XYZ.png")
if not node.image.filepath_raw.endswith("_XYZ.png"):
node.image.filepath_raw = node.image.filepath_raw[:-4] + "_XYZ.png"
if node.name == "TLM_Lightmap_Extra":
img_path = node.image.filepath_raw[:-8] + "_W.png"
img = bpy.data.images.load(img_path)
node.image = img
bpy.data.images.load(img_path)
print("PREM Extra: " + img_path)
node.image.filepath_raw = img_path
node.image.colorspace_settings.name = "Linear"
except:
print("Error occured with postfix change for obj: " + obj.name)
for image in bpy.data.images:
image.reload()
@ -278,47 +454,59 @@ def applyAOPass():
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
for slot in obj.material_slots:
mat = slot.material
node_tree = mat.node_tree
nodes = mat.node_tree.nodes
for node in nodes:
if node.name == "Baked Image" or node.name == "TLM_Lightmap":
hidden = False
filepath = bpy.data.filepath
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
LightmapPath = node.image.filepath_raw
if not hidden:
filebase = os.path.basename(LightmapPath)
filename = os.path.splitext(filebase)[0]
extension = os.path.splitext(filebase)[1]
AOImagefile = filename[:-4] + "_ao"
AOImagePath = os.path.join(dirpath, AOImagefile + extension)
for slot in obj.material_slots:
mat = slot.material
node_tree = mat.node_tree
nodes = mat.node_tree.nodes
AOMap = nodes.new('ShaderNodeTexImage')
AOMap.name = "TLM_AOMap"
AOImage = bpy.data.images.load(AOImagePath)
AOMap.image = AOImage
AOMap.location = -800, 0
for node in nodes:
if node.name == "Baked Image" or node.name == "TLM_Lightmap":
AOMult = nodes.new(type="ShaderNodeMixRGB")
AOMult.name = "TLM_AOMult"
AOMult.blend_type = 'MULTIPLY'
AOMult.inputs[0].default_value = 1.0
AOMult.location = -300, 300
filepath = bpy.data.filepath
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
multyNode = nodes["Lightmap_Multiplication"]
mainNode = nodes["Principled BSDF"]
UVMapNode = nodes["Lightmap_UV"]
LightmapPath = node.image.filepath_raw
node_tree.links.remove(multyNode.outputs[0].links[0])
filebase = os.path.basename(LightmapPath)
filename = os.path.splitext(filebase)[0]
extension = os.path.splitext(filebase)[1]
AOImagefile = filename[:-4] + "_ao"
AOImagePath = os.path.join(dirpath, AOImagefile + extension)
node_tree.links.new(multyNode.outputs[0], AOMult.inputs[1])
node_tree.links.new(AOMap.outputs[0], AOMult.inputs[2])
node_tree.links.new(AOMult.outputs[0], mainNode.inputs[0])
node_tree.links.new(UVMapNode.outputs[0], AOMap.inputs[0])
AOMap = nodes.new('ShaderNodeTexImage')
AOMap.name = "TLM_AOMap"
AOImage = bpy.data.images.load(AOImagePath)
AOMap.image = AOImage
AOMap.location = -800, 0
AOMult = nodes.new(type="ShaderNodeMixRGB")
AOMult.name = "TLM_AOMult"
AOMult.blend_type = 'MULTIPLY'
AOMult.inputs[0].default_value = 1.0
AOMult.location = -300, 300
multyNode = nodes["Lightmap_Multiplication"]
mainNode = nodes["Principled BSDF"]
UVMapNode = nodes["Lightmap_UV"]
node_tree.links.remove(multyNode.outputs[0].links[0])
node_tree.links.new(multyNode.outputs[0], AOMult.inputs[1])
node_tree.links.new(AOMap.outputs[0], AOMult.inputs[2])
node_tree.links.new(AOMult.outputs[0], mainNode.inputs[0])
node_tree.links.new(UVMapNode.outputs[0], AOMap.inputs[0])
def load_library(asset_name):

View File

@ -1,4 +1,4 @@
import bpy, math
import bpy, math, time
from . import cache
from .. utility import *
@ -23,6 +23,18 @@ def init(self, prev_container):
configure_meshes(self)
print("Config mesh catch omitted: REMEMBER TO SET IT BACK NAXELA")
# try:
# configure_meshes(self)
# except Exception as e:
# print("An error occured during mesh configuration. See error below:")
# print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
# if not bpy.context.scene.TLM_SceneProperties.tlm_verbose:
# print("Turn on verbose mode to get more detail.")
def configure_world():
pass
@ -32,13 +44,17 @@ def configure_lights():
def configure_meshes(self):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Configuring meshes")
print("Configuring meshes: Start")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Configuring meshes: Material restore")
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
cache.backup_material_restore(obj)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Configuring meshes: Material rename check")
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
@ -62,9 +78,61 @@ def configure_meshes(self):
scene = bpy.context.scene
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Object: Setting UV, converting modifiers and prepare channels")
#OBJECT: Set UV, CONVERT AND PREPARE
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
hidden = False
#We check if the object is hidden
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
#We check if the object's collection is hidden
collections = obj.users_collection
for collection in collections:
if collection.hide_viewport:
hidden = True
if collection.hide_render:
hidden = True
try:
if collection.name in bpy.context.scene.view_layers[0].layer_collection.children:
if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport:
hidden = True
except:
print("Error: Could not find collection: " + collection.name)
#Additional check for zero poly meshes
mesh = obj.data
if (len(mesh.polygons)) < 1:
print("Found an object with zero polygons. Skipping object: " + obj.name)
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use and not hidden:
print("Preparing: UV initiation for object: " + obj.name)
if len(obj.data.vertex_colors) < 1:
obj.data.vertex_colors.new(name="TLM")
if scene.TLM_SceneProperties.tlm_reset_uv:
uv_layers = obj.data.uv_layers
uv_channel = "UVMap_Lightmap"
for uvlayer in uv_layers:
if uvlayer.name == uv_channel:
uv_layers.remove(uvlayer)
if scene.TLM_SceneProperties.tlm_apply_on_unwrap:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
@ -73,6 +141,17 @@ def configure_meshes(self):
obj.select_set(True)
bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
if scene.TLM_SceneProperties.tlm_apply_modifiers:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Applying modifiers to: " + obj.name)
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.convert(target='MESH')
for slot in obj.material_slots:
material = slot.material
skipIncompatibleMaterials(material)
obj.hide_select = False #Remember to toggle this back
for slot in obj.material_slots:
if "." + slot.name + '_Original' in bpy.data.materials:
@ -80,96 +159,204 @@ def configure_meshes(self):
print("The material: " + slot.name + " shifted to " + "." + slot.name + '_Original')
slot.material = bpy.data.materials["." + slot.name + '_Original']
#ATLAS
#ATLAS UV PROJECTING
print("PREPARE: ATLAS")
for atlasgroup in scene.TLM_AtlasList:
print("Adding UV Projection for Atlas group: " + atlasgroup.name)
atlas = atlasgroup.name
atlas_items = []
bpy.ops.object.select_all(action='DESELECT')
#Atlas: Set UV, CONVERT AND PREPARE
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if obj.TLM_ObjectProperties.tlm_atlas_pointer == atlasgroup.name:
uv_layers = obj.data.uv_layers
hidden = False
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel
else:
uv_channel = "UVMap_Lightmap"
#We check if the object is hidden
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
if not uv_channel in uv_layers:
#We check if the object's collection is hidden
collections = obj.users_collection
for collection in collections:
if collection.hide_viewport:
hidden = True
if collection.hide_render:
hidden = True
try:
if collection.name in bpy.context.scene.view_layers[0].layer_collection.children:
if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport:
hidden = True
except:
print("Error: Could not find collection: " + collection.name)
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA" and not hidden:
uv_layers = obj.data.uv_layers
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel
else:
uv_channel = "UVMap_Lightmap"
if not uv_channel in uv_layers:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("UV map created for object: " + obj.name)
uvmap = uv_layers.new(name=uv_channel)
uv_layers.active_index = len(uv_layers) - 1
else:
print("Existing UV map found for object: " + obj.name)
for i in range(0, len(uv_layers)):
if uv_layers[i].name == 'UVMap_Lightmap':
uv_layers.active_index = i
break
atlas_items.append(obj)
obj.select_set(True)
if atlasgroup.tlm_atlas_lightmap_unwrap_mode == "SmartProject":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("UV map created for object: " + obj.name)
uvmap = uv_layers.new(name=uv_channel)
uv_layers.active_index = len(uv_layers) - 1
print("Atlasgroup Smart Project for: " + str(atlas_items))
for obj in atlas_items:
print("Applying Smart Project to: ")
print(obj.name + ": Active UV: " + obj.data.uv_layers[obj.data.uv_layers.active_index].name)
if len(atlas_items) > 0:
bpy.context.view_layer.objects.active = atlas_items[0]
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
#API changes in 2.91 causes errors:
if (2, 91, 0) > bpy.app.version:
bpy.ops.uv.smart_project(angle_limit=45.0, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, user_area_weight=1.0, use_aspect=True, stretch_to_bounds=False)
else:
angle = math.radians(45.0)
bpy.ops.uv.smart_project(angle_limit=angle, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, area_weight=1.0, correct_aspect=True, scale_to_bounds=False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
print("Smart project done.")
elif atlasgroup.tlm_atlas_lightmap_unwrap_mode == "Lightmap":
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.uv.lightmap_pack('EXEC_SCREEN', PREF_CONTEXT='ALL_FACES', PREF_MARGIN_DIV=atlasgroup.tlm_atlas_unwrap_margin)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
elif atlasgroup.tlm_atlas_lightmap_unwrap_mode == "Xatlas":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Using Xatlas on Atlas Group: " + atlas)
for obj in atlas_items:
obj.select_set(True)
if len(atlas_items) > 0:
bpy.context.view_layer.objects.active = atlas_items[0]
bpy.ops.object.mode_set(mode='EDIT')
Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj)
bpy.ops.object.mode_set(mode='OBJECT')
else:
print("Existing UV map found for object: " + obj.name)
for i in range(0, len(uv_layers)):
if uv_layers[i].name == 'UVMap_Lightmap':
uv_layers.active_index = i
break
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Copied Existing UV Map for Atlas Group: " + atlas)
atlas_items.append(obj)
obj.select_set(True)
if atlasgroup.tlm_use_uv_packer:
bpy.ops.object.select_all(action='DESELECT')
for obj in atlas_items:
obj.select_set(True)
if len(atlas_items) > 0:
bpy.context.view_layer.objects.active = atlas_items[0]
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
if atlasgroup.tlm_atlas_lightmap_unwrap_mode == "SmartProject":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Atlasgroup Smart Project for: " + str(atlas_items))
for obj in atlas_items:
print(obj.name + ": Active UV: " + obj.data.uv_layers[obj.data.uv_layers.active_index].name)
bpy.context.scene.UVPackerProps.uvp_padding = atlasgroup.tlm_uv_packer_padding
bpy.context.scene.UVPackerProps.uvp_engine = atlasgroup.tlm_uv_packer_packing_engine
if len(atlas_items) > 0:
bpy.context.view_layer.objects.active = atlas_items[0]
#print(x)
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
#API changes in 2.91 causes errors:
if (2, 91, 0) > bpy.app.version:
bpy.ops.uv.smart_project(angle_limit=45.0, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, user_area_weight=1.0, use_aspect=True, stretch_to_bounds=False)
else:
angle = math.radians(45.0)
bpy.ops.uv.smart_project(angle_limit=angle, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, area_weight=1.0, correct_aspect=True, scale_to_bounds=False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
elif atlasgroup.tlm_atlas_lightmap_unwrap_mode == "Lightmap":
print("!!!!!!!!!!!!!!!!!!!!! Using UV Packer on: " + obj.name)
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.uv.lightmap_pack('EXEC_SCREEN', PREF_CONTEXT='ALL_FACES', PREF_MARGIN_DIV=atlasgroup.tlm_atlas_unwrap_margin)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
if uv_layers.active == "UVMap_Lightmap":
print("YES")
else:
print("NO")
uv_layers.active_index = len(uv_layers) - 1
elif atlasgroup.tlm_atlas_lightmap_unwrap_mode == "Xatlas":
if uv_layers.active == "UVMap_Lightmap":
print("YES")
else:
print("NO")
uv_layers.active_index = len(uv_layers) - 1
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Using Xatlas on Atlas Group: " + atlas)
bpy.ops.uvpackeroperator.packbtn()
for obj in atlas_items:
obj.select_set(True)
if len(atlas_items) > 0:
bpy.context.view_layer.objects.active = atlas_items[0]
# if bpy.context.scene.UVPackerProps.uvp_engine == "OP0":
# time.sleep(1)
# else:
# time.sleep(2)
time.sleep(2)
bpy.ops.object.mode_set(mode='EDIT')
#FIX THIS! MAKE A SEPARATE CALL. THIS IS A THREADED ASYNC
Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='OBJECT')
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Copied Existing UV Map for Atlas Group: " + atlas)
#print(x)
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
iterNum = iterNum + 1
#OBJECT UV PROJECTING
print("PREPARE: OBJECTS")
for obj in bpy.context.scene.objects:
if obj.name in bpy.context.view_layer.objects: #Possible fix for view layer error
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
hidden = False
#We check if the object is hidden
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
#We check if the object's collection is hidden
collections = obj.users_collection
for collection in collections:
if collection.hide_viewport:
hidden = True
if collection.hide_render:
hidden = True
try:
if collection.name in bpy.context.scene.view_layers[0].layer_collection.children:
if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport:
hidden = True
except:
print("Error: Could not find collection: " + collection.name)
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use and not hidden:
objWasHidden = False
@ -189,10 +376,14 @@ def configure_meshes(self):
active = obs.active
#Provide material if none exists
print("Preprocessing material for: " + obj.name)
preprocess_material(obj, scene)
#UV Layer management here
if not obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
print("Managing layer for Obj: " + obj.name)
uv_layers = obj.data.uv_layers
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
@ -225,6 +416,7 @@ def configure_meshes(self):
else:
angle = math.radians(45.0)
bpy.ops.uv.smart_project(angle_limit=angle, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, area_weight=1.0, correct_aspect=True, scale_to_bounds=False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
@ -242,6 +434,46 @@ def configure_meshes(self):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Copied Existing UV Map for object: " + obj.name)
if obj.TLM_ObjectProperties.tlm_use_uv_packer:
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.context.scene.UVPackerProps.uvp_padding = obj.TLM_ObjectProperties.tlm_uv_packer_padding
bpy.context.scene.UVPackerProps.uvp_engine = obj.TLM_ObjectProperties.tlm_uv_packer_packing_engine
#print(x)
print("!!!!!!!!!!!!!!!!!!!!! Using UV Packer on: " + obj.name)
if uv_layers.active == "UVMap_Lightmap":
print("YES")
else:
print("NO")
uv_layers.active_index = len(uv_layers) - 1
if uv_layers.active == "UVMap_Lightmap":
print("YES")
else:
print("NO")
uv_layers.active_index = len(uv_layers) - 1
bpy.ops.uvpackeroperator.packbtn()
if bpy.context.scene.UVPackerProps.uvp_engine == "OP0":
time.sleep(1)
else:
time.sleep(2)
#FIX THIS! MAKE A SEPARATE CALL. THIS IS A THREADED ASYNC
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
#print(x)
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Existing UV map found for obj: " + obj.name)
@ -286,6 +518,13 @@ def configure_meshes(self):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("The material group is not supported!")
if (mainNode.type == "ShaderNodeMixRGB"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Mix shader found")
#Skip for now
slot.material.TLM_ignore = True
if (mainNode.type == "BSDF_PRINCIPLED"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("BSDF_Principled")
@ -301,6 +540,7 @@ def configure_meshes(self):
#Clamp metallic
if bpy.context.scene.TLM_SceneProperties.tlm_metallic_clamp == "limit":
MainMetNodeSocket = mainNode.inputs[4]
if not len(MainMetNodeSocket.links) == 0:
nodes = nodetree.nodes
@ -308,14 +548,19 @@ def configure_meshes(self):
MetClampNode.location = (-200,150)
MetClampNode.inputs[2].default_value = 0.9
minput = mainNode.inputs[4].links[0] #Metal input socket
moutput = mainNode.inputs[4].links[0].from_node #Metal output node
nodetree.links.remove(moutput.outputs[0].links[0]) #Works
nodetree.links.new(moutput.outputs[0], MetClampNode.inputs[0]) #minput node to clamp node
nodetree.links.new(MetClampNode.outputs[0],MainMetNodeSocket) #clamp node to metinput
moutput = mainNode.inputs[4].links[0].from_socket #Output socket
nodetree.links.remove(minput)
nodetree.links.new(moutput, MetClampNode.inputs[0]) #minput node to clamp node
nodetree.links.new(MetClampNode.outputs[0], MainMetNodeSocket) #clamp node to metinput
else:
if mainNode.inputs[4].default_value > 0.9:
mainNode.inputs[4].default_value = 0.9
elif bpy.context.scene.TLM_SceneProperties.tlm_metallic_clamp == "zero":
MainMetNodeSocket = mainNode.inputs[4]
if not len(MainMetNodeSocket.links) == 0:
nodes = nodetree.nodes
@ -323,13 +568,18 @@ def configure_meshes(self):
MetClampNode.location = (-200,150)
MetClampNode.inputs[2].default_value = 0.0
minput = mainNode.inputs[4].links[0] #Metal input socket
moutput = mainNode.inputs[4].links[0].from_node #Metal output node
nodetree.links.remove(moutput.outputs[0].links[0]) #Works
nodetree.links.new(moutput.outputs[0], MetClampNode.inputs[0]) #minput node to clamp node
nodetree.links.new(MetClampNode.outputs[0],MainMetNodeSocket) #clamp node to metinput
moutput = mainNode.inputs[4].links[0].from_socket #Output socket
nodetree.links.remove(minput)
nodetree.links.new(moutput, MetClampNode.inputs[0]) #minput node to clamp node
nodetree.links.new(MetClampNode.outputs[0], MainMetNodeSocket) #clamp node to metinput
else:
mainNode.inputs[4].default_value = 0.0
else: #Skip
pass
if (mainNode.type == "BSDF_DIFFUSE"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("BSDF_Diffuse")
@ -526,13 +776,22 @@ def set_settings():
sceneProperties = scene.TLM_SceneProperties
engineProperties = scene.TLM_EngineProperties
cycles.device = scene.TLM_EngineProperties.tlm_mode
if cycles.device == "GPU":
scene.render.tile_x = 256
scene.render.tile_y = 256
else:
scene.render.tile_x = 32
scene.render.tile_y = 32
print(bpy.app.version)
if (3, 0, 0) >= bpy.app.version:
if cycles.device == "GPU":
scene.cycles.tile_size = 256
else:
scene.cycles.tile_size = 32
else:
if cycles.device == "GPU":
scene.render.tile_x = 256
scene.render.tile_y = 256
else:
scene.render.tile_x = 32
scene.render.tile_y = 32
if engineProperties.tlm_quality == "0":
cycles.samples = 32
@ -613,4 +872,45 @@ def store_existing(prev_container):
bpy.context.view_layer.objects.active,
selected,
[scene.render.resolution_x, scene.render.resolution_y]
]
]
def skipIncompatibleMaterials(material):
node_tree = material.node_tree
nodes = material.node_tree.nodes
#ADD OR MIX SHADER? CUSTOM/GROUP?
#IF Principled has emissive or transparency?
SkipMatList = ["EMISSION",
"BSDF_TRANSPARENT",
"BACKGROUND",
"BSDF_HAIR",
"BSDF_HAIR_PRINCIPLED",
"HOLDOUT",
"PRINCIPLED_VOLUME",
"BSDF_REFRACTION",
"EEVEE_SPECULAR",
"BSDF_TRANSLUCENT",
"VOLUME_ABSORPTION",
"VOLUME_SCATTER"]
#Find output node
outputNode = nodes[0]
if(outputNode.type != "OUTPUT_MATERIAL"):
for node in node_tree.nodes:
if node.type == "OUTPUT_MATERIAL":
outputNode = node
break
#Find mainnode
mainNode = outputNode.inputs[0].links[0].from_node
if mainNode.type in SkipMatList:
material.TLM_ignore = True
print("Ignored material: " + material.name)
def packUVPack():
pass

View File

@ -67,14 +67,14 @@ class TLM_Integrated_Denoise:
filename, file_extension = os.path.splitext(image)
filename = filename[:-6]
bpy.data.scenes["Scene"].render.filepath = self.image_output_destination + "/" + filename + "_denoised" + file_extension
bpy.context.scene.render.filepath = self.image_output_destination + "/" + filename + "_denoised" + file_extension
denoised_image_path = self.image_output_destination
bpy.data.scenes["Scene"].render.image_settings.file_format = "HDR"
bpy.context.scene.render.image_settings.file_format = "HDR"
bpy.ops.render.render(write_still=True)
#Cleanup
comp_nodes = [image_node, denoise_node, comp_node]
for node in comp_nodes:
tree.nodes.remove(node)
tree.nodes.remove(node)

View File

@ -74,7 +74,7 @@ class TLM_OIDN_Denoise:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Loaded image: " + str(loaded_image))
verbose = bpy.context.scene.TLM_SceneProperties.tlm_verbose
verbose = self.oidnProperties.tlm_oidn_verbose
affinity = self.oidnProperties.tlm_oidn_affinity
if verbose:

View File

@ -1,10 +1,43 @@
import bpy, math, os, gpu, bgl
import bpy, math, os, gpu, bgl, importlib
import numpy as np
from . import utility
from fractions import Fraction
from gpu_extras.batch import batch_for_shader
def splitLogLuvAlphaAtlas(imageIn, outDir, quality):
pass
def splitLogLuvAlpha(imageIn, outDir, quality):
bpy.app.driver_namespace["logman"].append("Starting LogLuv split for: " + str(imageIn))
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
print("CV2 not found - Ignoring filtering")
return 0
else:
cv2 = importlib.__import__("cv2")
print(imageIn)
image = cv2.imread(imageIn, cv2.IMREAD_UNCHANGED)
#cv2.imshow('image', image)
split = cv2.split(image)
merged = cv2.merge([split[0], split[1], split[2]])
alpha = split[3]
#b,g,r = cv2.split(image)
#merged = cv2.merge([b, g, r])
#alpha = cv2.merge([a,a,a])
image_name = os.path.basename(imageIn)[:-4]
#os.path.join(outDir, image_name+"_XYZ.png")
cv2.imwrite(os.path.join(outDir, image_name+"_XYZ.png"), merged)
cv2.imwrite(os.path.join(outDir, image_name+"_W.png"), alpha)
def encodeLogLuvGPU(image, outDir, quality):
bpy.app.driver_namespace["logman"].append("Starting LogLuv encode for: " + str(image.name))
input_image = bpy.data.images[image.name]
image_name = input_image.name
@ -139,9 +172,6 @@ def encodeLogLuvGPU(image, outDir, quality):
bpy.context.scene.render.image_settings.quality = quality
#input_image.save_render(filepath = input_image.filepath_raw, scene = bpy.context.scene)
input_image.save()
#Todo - Find a way to save
#bpy.ops.image.save_all_modified()
def encodeImageRGBDGPU(image, maxRange, outDir, quality):
input_image = bpy.data.images[image.name]

View File

@ -7,7 +7,7 @@ class ViewportDraw:
bakefile = "TLM_Overlay.png"
scriptDir = os.path.dirname(os.path.realpath(__file__))
bakefile_path = os.path.abspath(os.path.join(scriptDir, '..', '..', 'assets/' + bakefile))
bakefile_path = os.path.abspath(os.path.join(scriptDir, '..', '..', 'assets', bakefile))
image_name = "TLM_Overlay.png"
@ -15,7 +15,13 @@ class ViewportDraw:
print("Self path: " + bakefile_path)
image = bpy.data.images[image_name]
for img in bpy.data.images:
if img.filepath.endswith(image_name):
image = img
break
if not image:
image = bpy.data.images[image_name]
x = 15
y = 15
@ -51,7 +57,11 @@ class ViewportDraw:
if self.image:
bgl.glEnable(bgl.GL_BLEND)
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.image.bindcode)
try:
bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.image.bindcode)
except:
bpy.types.SpaceView3D.draw_handler_remove(self.handle2, 'WINDOW')
self.shader.bind()
self.shader.uniform_int("image", 0)
@ -64,4 +74,4 @@ class ViewportDraw:
def remove_handle(self):
#bpy.types.SpaceView3D.draw_handler_remove(self.handle, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self.handle2, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self.handle2, 'WINDOW')

View File

@ -0,0 +1,21 @@
import bpy
import datetime
class TLM_Logman:
_log = []
def __init__(self):
print("Logger started Init")
self.append("Logger started.")
def append(self, appended):
self._log.append(str(datetime.datetime.now()) + ": " + str(appended))
#TODO!
def stats():
pass
def dumpLog(self):
for line in self._log:
print(line)

View File

@ -91,6 +91,8 @@ def postpack():
packer[atlas.name] = newPacker(PackingMode.Offline, PackingBin.BFF, rotation=False)
bpy.app.driver_namespace["logman"].append("Postpacking: " + str(atlas.name))
if scene.TLM_EngineProperties.tlm_setting_supersample == "2x":
supersampling_scale = 2
elif scene.TLM_EngineProperties.tlm_setting_supersample == "4x":
@ -115,9 +117,13 @@ def postpack():
rect.append((res, res, obj.name))
#Add rect to bin
for r in rect:
packer[atlas.name].add_rect(*r)
print("Rects: " + str(rect))
print("Bins:" + str(packer[atlas.name]))
packedAtlas[atlas.name] = np.zeros((atlas_resolution,atlas_resolution, 3), dtype="float32")
#Continue here...overwrite value if using 8-bit encoding
@ -140,6 +146,8 @@ def postpack():
for idy, rect in enumerate(packer[atlas.name].rect_list()):
print("Packing atlas at: " + str(rect))
aob = rect[5]
src = cv2.imread(os.path.join(lightmap_directory, aob + end + formatEnc), image_channel_depth) #"_baked.hdr"
@ -148,8 +156,11 @@ def postpack():
x,y,w,h = rect[1],rect[2],rect[3],rect[4]
print(src.shape)
print(packedAtlas[atlas.name].shape)
print("Obj Shape: " + str(src.shape))
print("Atlas shape: " + str(packedAtlas[atlas.name].shape))
print("Bin Pos: ",x,y,w,h)
packedAtlas[atlas.name][y:h+y, x:w+x] = src
@ -167,34 +178,64 @@ def postpack():
print("UVLayer set to: " + str(obj.data.uv_layers.active_index))
atlasRes = atlas_resolution
texRes = rect[3] #Any dimension w/h (square)
ratio = texRes/atlasRes
scaleUV(obj.data.uv_layers.active, (ratio, ratio), (0,1))
print(rect)
#Postpack error here...
for uv_verts in obj.data.uv_layers.active.data:
#For each vert
#NOTES! => X FUNKER
#TODO => Y
#[0] = bin index
#[1] = x
#[2] = y (? + 1)
#[3] = w
#[4] = h
vertex_x = uv_verts.uv[0] + (rect[1]/atlasRes) #WORKING!
vertex_y = uv_verts.uv[1] - (rect[2]/atlasRes) # + ((rect[2]-rect[4])/atlasRes) # # + (1-((rect[1]-rect[4])/atlasRes))
#tr = "X: {0} + ({1}/{2})".format(uv_verts.uv[0],rect[1],atlasRes)
#print(tr)
#vertex_y = 1 - (uv_verts.uv[1]) uv_verts.uv[1] + (rect[1]/atlasRes)
#SET UV LAYER TO
atlasRes = atlas_resolution
texRes = rect[3]
x,y,w,z = x,y,texRes,texRes
# atlasRes = atlas_resolution
# texRes = rect[3] #Any dimension w/h (square)
# print(texRes)
# #texRes = 0.0,0.0
# #x,y,w,z = x,y,texRes,texRes
# x,y,w,z = x,y,0,0
ratio = atlasRes/texRes
# ratio = atlasRes/texRes
if x == 0:
x_offset = 0
else:
x_offset = 1/(atlasRes/x)
# if x == 0:
# x_offset = 0
# else:
# x_offset = 1/(atlasRes/x)
if y == 0:
y_offset = 0
else:
y_offset = 1/(atlasRes/y)
# if y == 0:
# y_offset = 0
# else:
# y_offset = 1/(atlasRes/y)
vertex_x = (uv_verts.uv[0] * 1/(ratio)) + x_offset
vertex_y = (1 - ((uv_verts.uv[1] * 1/(ratio)) + y_offset))
# vertex_x = (uv_verts.uv[0] * 1/(ratio)) + x_offset
# vertex_y = (1 - ((uv_verts.uv[1] * 1/(ratio)) + y_offset))
#TO FIX:
#SELECT ALL
#Scale Y => -1
uv_verts.uv[0] = vertex_x
uv_verts.uv[1] = vertex_y
scaleUV(obj.data.uv_layers.active, (1, -1), getBoundsCenter(obj.data.uv_layers.active))
print(getCenter(obj.data.uv_layers.active))
#scaleUV(obj.data.uv_layers.active, (1, -1), getBoundsCenter(obj.data.uv_layers.active))
#print(getCenter(obj.data.uv_layers.active))
cv2.imwrite(os.path.join(lightmap_directory, atlas.name + end + formatEnc), packedAtlas[atlas.name])
print("Written: " + str(os.path.join(lightmap_directory, atlas.name + end + formatEnc)))
@ -221,8 +262,12 @@ def postpack():
node.image = atlasImage
os.remove(os.path.join(lightmap_directory, obj.name + end + formatEnc))
existing_image.user_clear()
#print("Seeking for: " + atlasImage.filepath_raw)
#print(x)
if(os.path.exists(os.path.join(lightmap_directory, obj.name + end + formatEnc))):
os.remove(os.path.join(lightmap_directory, obj.name + end + formatEnc))
existing_image.user_clear()
#Add dilation map here...
for obj in bpy.context.scene.objects:

View File

@ -664,11 +664,14 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
def transfer_assets(copy, source, destination):
for filename in glob.glob(os.path.join(source, '*.*')):
shutil.copy(filename, destination)
try:
shutil.copy(filename, destination)
except shutil.SameFileError:
pass
def transfer_load():
load_folder = bpy.path.abspath(os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_SceneProperties.tlm_load_folder))
lightmap_folder = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
print(load_folder)
print(lightmap_folder)
transfer_assets(True, load_folder, lightmap_folder)
transfer_assets(True, load_folder, lightmap_folder)

View File

@ -85,9 +85,6 @@ class ARM_PT_ObjectPropsPanel(bpy.types.Panel):
# Lightmapping props
if obj.type == "MESH":
row = layout.row(align=True)
scene = bpy.context.scene
if scene == None:
return
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_use")
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
@ -122,6 +119,7 @@ class ARM_PT_ObjectPropsPanel(bpy.types.Panel):
row.prop(obj.TLM_ObjectProperties, "tlm_postpack_object")
row = layout.row()
if obj.TLM_ObjectProperties.tlm_postpack_object and obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode != "AtlasGroupA":
if scene.TLM_PostAtlasListItem >= 0 and len(scene.TLM_PostAtlasList) > 0:
row = layout.row()
@ -162,6 +160,15 @@ class ARM_PT_ObjectPropsPanel(bpy.types.Panel):
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
#If UV Packer installed
if "UV-Packer" in bpy.context.preferences.addons.keys():
row.prop(obj.TLM_ObjectProperties, "tlm_use_uv_packer")
if obj.TLM_ObjectProperties.tlm_use_uv_packer:
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_uv_packer_padding")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_uv_packer_packing_engine")
class ARM_PT_ModifiersPropsPanel(bpy.types.Panel):
bl_label = "Armory Props"
bl_space_type = "PROPERTIES"