Update lightmapper to Blender 2.9+

Finalized update to support Blender 2.9+ as well as new features, fixes and more stability
This commit is contained in:
Alexander Kleemann 2021-03-18 18:49:30 +01:00
parent cbb8ee4bae
commit ef8fb21536
40 changed files with 3348 additions and 960 deletions

View file

@ -1 +1 @@
__all__ = ('Operators', 'Properties', 'Utility', 'Keymap')
__all__ = ('Operators', 'Panels', 'Properties', 'Preferences', 'Utility', 'Keymap')

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

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

View file

@ -9,6 +9,8 @@ def register():
winman = bpy.context.window_manager
keyman = winman.keyconfigs.addon.keymaps.new(name='Window', space_type='EMPTY', region_type="WINDOW")
#TODO - In Armory3D, merge with keymap.py
keyman.keymap_items.new('tlm.build_lightmaps', type='F6', value='PRESS')
keyman.keymap_items.new('tlm.clean_lightmaps', type='F7', value='PRESS')
tlm_keymaps.append(keyman)

View file

@ -6,10 +6,11 @@ classes = [
tlm.TLM_BuildLightmaps,
tlm.TLM_CleanLightmaps,
tlm.TLM_ExploreLightmaps,
tlm.TLM_EnableSelection,
tlm.TLM_EnableSet,
tlm.TLM_DisableSelection,
tlm.TLM_RemoveLightmapUV,
tlm.TLM_SelectLightmapped,
tlm.TLM_ToggleTexelDensity,
installopencv.TLM_Install_OpenCV,
tlm.TLM_AtlasListNewItem,
tlm.TLM_AtlastListDeleteItem,
@ -20,6 +21,8 @@ classes = [
tlm.TLM_StartServer,
tlm.TLM_BuildEnvironmentProbes,
tlm.TLM_CleanBuildEnvironmentProbes,
tlm.TLM_PrepareUVMaps,
tlm.TLM_LoadLightmaps,
imagetools.TLM_ImageUpscale,
imagetools.TLM_ImageDownscale

View file

@ -1,4 +1,4 @@
import bpy, os, time
import bpy, os, time, importlib
class TLM_ImageUpscale(bpy.types.Operator):
bl_idname = "tlm.image_upscale"
@ -8,6 +8,69 @@ class TLM_ImageUpscale(bpy.types.Operator):
def invoke(self, context, event):
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
print("CV2 not found - Ignoring filtering")
return 0
else:
cv2 = importlib.__import__("cv2")
for area in bpy.context.screen.areas:
if area.type == "IMAGE_EDITOR":
active_image = area.spaces.active.image
if active_image.source == "FILE":
img_path = active_image.filepath_raw
filename = os.path.basename(img_path)
basename = os.path.splitext(filename)[0]
extension = os.path.splitext(filename)[1]
size_x = active_image.size[0]
size_y = active_image.size[1]
dir_path = os.path.dirname(os.path.realpath(img_path))
#newfile = os.path.join(dir_path, basename + "_" + str(size_x) + "_" + str(size_y) + extension)
newfile = os.path.join(dir_path, basename + extension)
os.rename(img_path, newfile)
basefile = cv2.imread(newfile, cv2.IMREAD_UNCHANGED)
scale_percent = 200 # percent of original size
width = int(basefile.shape[1] * scale_percent / 100)
height = int(basefile.shape[0] * scale_percent / 100)
dim = (width, height)
if active_image.TLM_ImageProperties.tlm_image_scale_method == "Nearest":
interp = cv2.INTER_NEAREST
elif active_image.TLM_ImageProperties.tlm_image_scale_method == "Area":
interp = cv2.INTER_AREA
elif active_image.TLM_ImageProperties.tlm_image_scale_method == "Linear":
interp = cv2.INTER_LINEAR
elif active_image.TLM_ImageProperties.tlm_image_scale_method == "Cubic":
interp = cv2.INTER_CUBIC
elif active_image.TLM_ImageProperties.tlm_image_scale_method == "Lanczos":
interp = cv2.INTER_LANCZOS4
resized = cv2.resize(basefile, dim, interpolation = interp)
#resizedFile = os.path.join(dir_path, basename + "_" + str(width) + "_" + str(height) + extension)
resizedFile = os.path.join(dir_path, basename + extension)
cv2.imwrite(resizedFile, resized)
active_image.filepath_raw = resizedFile
bpy.ops.image.reload()
print(newfile)
print(img_path)
else:
print("Please save image")
print("Upscale")
return {'RUNNING_MODAL'}
@ -20,6 +83,111 @@ class TLM_ImageDownscale(bpy.types.Operator):
def invoke(self, context, event):
print("Downscale")
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
print("CV2 not found - Ignoring filtering")
return 0
else:
cv2 = importlib.__import__("cv2")
for area in bpy.context.screen.areas:
if area.type == "IMAGE_EDITOR":
active_image = area.spaces.active.image
if active_image.source == "FILE":
img_path = active_image.filepath_raw
filename = os.path.basename(img_path)
basename = os.path.splitext(filename)[0]
extension = os.path.splitext(filename)[1]
size_x = active_image.size[0]
size_y = active_image.size[1]
dir_path = os.path.dirname(os.path.realpath(img_path))
#newfile = os.path.join(dir_path, basename + "_" + str(size_x) + "_" + str(size_y) + extension)
newfile = os.path.join(dir_path, basename + extension)
os.rename(img_path, newfile)
basefile = cv2.imread(newfile, cv2.IMREAD_UNCHANGED)
scale_percent = 50 # percent of original size
width = int(basefile.shape[1] * scale_percent / 100)
height = int(basefile.shape[0] * scale_percent / 100)
dim = (width, height)
if dim[0] > 1 or dim[1] > 1:
if active_image.TLM_ImageProperties.tlm_image_scale_method == "Nearest":
interp = cv2.INTER_NEAREST
elif active_image.TLM_ImageProperties.tlm_image_scale_method == "Area":
interp = cv2.INTER_AREA
elif active_image.TLM_ImageProperties.tlm_image_scale_method == "Linear":
interp = cv2.INTER_LINEAR
elif active_image.TLM_ImageProperties.tlm_image_scale_method == "Cubic":
interp = cv2.INTER_CUBIC
elif active_image.TLM_ImageProperties.tlm_image_scale_method == "Lanczos":
interp = cv2.INTER_LANCZOS4
resized = cv2.resize(basefile, dim, interpolation = interp)
#resizedFile = os.path.join(dir_path, basename + "_" + str(width) + "_" + str(height) + extension)
resizedFile = os.path.join(dir_path, basename + extension)
cv2.imwrite(resizedFile, resized)
active_image.filepath_raw = resizedFile
bpy.ops.image.reload()
print(newfile)
print(img_path)
else:
print("Please save image")
print("Upscale")
return {'RUNNING_MODAL'}
class TLM_ImageSwitchUp(bpy.types.Operator):
bl_idname = "tlm.image_switchup"
bl_label = "Quickswitch Up"
bl_description = "Switches to a cached upscaled image"
bl_options = {'REGISTER', 'UNDO'}
def invoke(self, context, event):
for area in bpy.context.screen.areas:
if area.type == "IMAGE_EDITOR":
active_image = area.spaces.active.image
if active_image.source == "FILE":
img_path = active_image.filepath_raw
filename = os.path.basename(img_path)
print("Switch up")
return {'RUNNING_MODAL'}
class TLM_ImageSwitchDown(bpy.types.Operator):
bl_idname = "tlm.image_switchdown"
bl_label = "Quickswitch Down"
bl_description = "Switches to a cached downscaled image"
bl_options = {'REGISTER', 'UNDO'}
def invoke(self, context, event):
for area in bpy.context.screen.areas:
if area.type == "IMAGE_EDITOR":
active_image = area.spaces.active.image
if active_image.source == "FILE":
img_path = active_image.filepath_raw
filename = os.path.basename(img_path)
print("Switch Down")
return {'RUNNING_MODAL'}

View file

@ -21,7 +21,10 @@ class TLM_Install_OpenCV(bpy.types.Operator):
print("Module OpenCV")
pythonbinpath = bpy.app.binary_path_python
if (2, 91, 0) > bpy.app.version:
pythonbinpath = bpy.app.binary_path_python
else:
pythonbinpath = sys.executable
if platform.system() == "Windows":
pythonlibpath = os.path.join(os.path.dirname(os.path.dirname(pythonbinpath)), "lib")

View file

@ -1,9 +1,36 @@
import bpy, os, time, blf, webbrowser, platform
import bpy, os, time, blf, webbrowser, platform, numpy, bmesh
import math, subprocess, multiprocessing
from .. utility import utility
from .. utility import build
from .. utility.cycles import cache
from .. network import server
def setObjectLightmapByWeight(minimumRes, maximumRes, objWeight):
availableResolutions = [32,64,128,256,512,1024,2048,4096,8192]
minRes = minimumRes
minResIdx = availableResolutions.index(minRes)
maxRes = maximumRes
maxResIdx = availableResolutions.index(maxRes)
exampleWeight = objWeight
if minResIdx == maxResIdx:
pass
else:
increment = 1.0/(maxResIdx-minResIdx)
assortedRange = []
for a in numpy.arange(0.0, 1.0, increment):
assortedRange.append(round(a, 2))
assortedRange.append(1.0)
nearestWeight = min(assortedRange, key=lambda x:abs(x - exampleWeight))
return (availableResolutions[assortedRange.index(nearestWeight) + minResIdx])
class TLM_BuildLightmaps(bpy.types.Operator):
bl_idname = "tlm.build_lightmaps"
bl_label = "Build Lightmaps"
@ -52,13 +79,13 @@ class TLM_CleanLightmaps(bpy.types.Operator):
for file in os.listdir(dirpath):
os.remove(os.path.join(dirpath + "/" + file))
for obj in bpy.data.objects:
if obj.type == "MESH":
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)
for obj in bpy.data.objects:
if obj.type == "MESH":
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_rename(obj)
@ -75,8 +102,8 @@ class TLM_CleanLightmaps(bpy.types.Operator):
if image.name.endswith("_baked"):
bpy.data.images.remove(image, do_unlink=True)
for obj in bpy.data.objects:
if obj.type == "MESH":
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:
if obj.TLM_ObjectProperties.tlm_postpack_object:
@ -92,14 +119,17 @@ class TLM_CleanLightmaps(bpy.types.Operator):
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
#print(x)
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"
for i in range(0, len(uv_layers)):
if uv_layers[i].name == 'UVMap_Lightmap':
if uv_layers[i].name == uv_channel:
uv_layers.active_index = i
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Lightmap shift A")
break
bpy.ops.object.mode_set(mode='EDIT')
@ -111,9 +141,11 @@ class TLM_CleanLightmaps(bpy.types.Operator):
bpy.ops.object.mode_set(mode='OBJECT')
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
#print(obj.name + ": Active UV: " + obj.data.uv_layers[obj.data.uv_layers.active_index].name)
print("Resized for obj: " + obj.name)
if "Lightmap" in obj:
del obj["Lightmap"]
return {'FINISHED'}
class TLM_ExploreLightmaps(bpy.types.Operator):
@ -153,63 +185,285 @@ class TLM_ExploreLightmaps(bpy.types.Operator):
return {'FINISHED'}
class TLM_EnableSelection(bpy.types.Operator):
"""Enable for selection"""
bl_idname = "tlm.enable_selection"
bl_label = "Enable for selection"
bl_description = "Enable for selection"
class TLM_EnableSet(bpy.types.Operator):
"""Enable for set"""
bl_idname = "tlm.enable_set"
bl_label = "Enable for set"
bl_description = "Enable for set"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
for obj in bpy.context.selected_objects:
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True
weightList = {} #ObjName : [Dimension,Weight]
max = 0
if scene.TLM_SceneProperties.tlm_override_object_settings:
obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = scene.TLM_SceneProperties.tlm_mesh_lightmap_resolution
obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = scene.TLM_SceneProperties.tlm_mesh_lightmap_unwrap_mode
obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin = scene.TLM_SceneProperties.tlm_mesh_unwrap_margin
obj.TLM_ObjectProperties.tlm_postpack_object = scene.TLM_SceneProperties.tlm_postpack_object
if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene":
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
obj.TLM_ObjectProperties.tlm_atlas_pointer = scene.TLM_SceneProperties.tlm_atlas_pointer
print("Enabling for scene: " + obj.name)
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True
obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = bpy.context.scene.TLM_SceneProperties.tlm_mesh_lightmap_unwrap_mode
obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin = bpy.context.scene.TLM_SceneProperties.tlm_mesh_unwrap_margin
obj.TLM_ObjectProperties.tlm_postpack_object = bpy.context.scene.TLM_SceneProperties.tlm_postpack_object
obj.TLM_ObjectProperties.tlm_postatlas_pointer = scene.TLM_SceneProperties.tlm_postatlas_pointer
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
obj.TLM_ObjectProperties.tlm_atlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_atlas_pointer
obj.TLM_ObjectProperties.tlm_postatlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_postatlas_pointer
if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Single":
obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = scene.TLM_SceneProperties.tlm_mesh_lightmap_resolution
elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Dimension":
obj_dimensions = obj.dimensions.x * obj.dimensions.y * obj.dimensions.z
weightList[obj.name] = [obj_dimensions, 0]
if obj_dimensions > max:
max = obj_dimensions
elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Surface":
bm = bmesh.new()
bm.from_mesh(obj.data)
area = sum(f.calc_area() for f in bm.faces)
weightList[obj.name] = [area, 0]
if area > max:
max = area
elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Volume":
bm = bmesh.new()
bm.from_mesh(obj.data)
volume = float( bm.calc_volume())
weightList[obj.name] = [volume, 0]
if volume > max:
max = volume
elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection":
for obj in bpy.context.selected_objects:
if obj.type == "MESH":
print("Enabling for selection: " + obj.name)
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True
obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = bpy.context.scene.TLM_SceneProperties.tlm_mesh_lightmap_unwrap_mode
obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin = bpy.context.scene.TLM_SceneProperties.tlm_mesh_unwrap_margin
obj.TLM_ObjectProperties.tlm_postpack_object = bpy.context.scene.TLM_SceneProperties.tlm_postpack_object
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
obj.TLM_ObjectProperties.tlm_atlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_atlas_pointer
obj.TLM_ObjectProperties.tlm_postatlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_postatlas_pointer
if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Single":
obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = scene.TLM_SceneProperties.tlm_mesh_lightmap_resolution
elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Dimension":
obj_dimensions = obj.dimensions.x * obj.dimensions.y * obj.dimensions.z
weightList[obj.name] = [obj_dimensions, 0]
if obj_dimensions > max:
max = obj_dimensions
elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Surface":
bm = bmesh.new()
bm.from_mesh(obj.data)
area = sum(f.calc_area() for f in bm.faces)
weightList[obj.name] = [area, 0]
if area > max:
max = area
elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Volume":
bm = bmesh.new()
bm.from_mesh(obj.data)
volume = float( bm.calc_volume())
weightList[obj.name] = [volume, 0]
if volume > max:
max = volume
else: #Enabled
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
print("Enabling for designated: " + obj.name)
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = True
obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode = bpy.context.scene.TLM_SceneProperties.tlm_mesh_lightmap_unwrap_mode
obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin = bpy.context.scene.TLM_SceneProperties.tlm_mesh_unwrap_margin
obj.TLM_ObjectProperties.tlm_postpack_object = bpy.context.scene.TLM_SceneProperties.tlm_postpack_object
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
obj.TLM_ObjectProperties.tlm_atlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_atlas_pointer
obj.TLM_ObjectProperties.tlm_postatlas_pointer = bpy.context.scene.TLM_SceneProperties.tlm_postatlas_pointer
if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Single":
obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = scene.TLM_SceneProperties.tlm_mesh_lightmap_resolution
elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Dimension":
obj_dimensions = obj.dimensions.x * obj.dimensions.y * obj.dimensions.z
weightList[obj.name] = [obj_dimensions, 0]
if obj_dimensions > max:
max = obj_dimensions
elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Surface":
bm = bmesh.new()
bm.from_mesh(obj.data)
area = sum(f.calc_area() for f in bm.faces)
weightList[obj.name] = [area, 0]
if area > max:
max = area
elif bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight == "Volume":
bm = bmesh.new()
bm.from_mesh(obj.data)
volume = float( bm.calc_volume())
weightList[obj.name] = [volume, 0]
if volume > max:
max = volume
if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene":
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight != "Single":
for key in weightList:
weightList[obj.name][1] = weightList[obj.name][0] / max
a = setObjectLightmapByWeight(int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_min), int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_max), weightList[obj.name][1])
print(str(a) + "/" + str(weightList[obj.name][1]))
print("Scale: " + str(weightList[obj.name][0]))
print("Obj: " + obj.name)
obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = str(a)
elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection":
for obj in bpy.context.selected_objects:
if obj.type == "MESH":
if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight != "Single":
for key in weightList:
weightList[obj.name][1] = weightList[obj.name][0] / max
a = setObjectLightmapByWeight(int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_min), int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_max), weightList[obj.name][1])
print(str(a) + "/" + str(weightList[obj.name][1]))
print("Scale: " + str(weightList[obj.name][0]))
print("Obj: " + obj.name)
obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = str(a)
else: #Enabled
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if bpy.context.scene.TLM_SceneProperties.tlm_resolution_weight != "Single":
for key in weightList:
weightList[obj.name][1] = weightList[obj.name][0] / max
a = setObjectLightmapByWeight(int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_min), int(bpy.context.scene.TLM_SceneProperties.tlm_resolution_max), weightList[obj.name][1])
print(str(a) + "/" + str(weightList[obj.name][1]))
print("Scale: " + str(weightList[obj.name][0]))
print("Obj: " + obj.name)
print("")
obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution = str(a)
return{'FINISHED'}
class TLM_DisableSelection(bpy.types.Operator):
"""Disable for selection"""
"""Disable for set"""
bl_idname = "tlm.disable_selection"
bl_label = "Disable for selection"
bl_label = "Disable for set"
bl_description = "Disable for selection"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
for obj in bpy.context.selected_objects:
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False
scene = context.scene
weightList = {} #ObjName : [Dimension,Weight]
max = 0
if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene":
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False
elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection":
for obj in bpy.context.selected_objects:
if obj.type == "MESH":
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False
else: #Enabled
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False
return{'FINISHED'}
class TLM_RemoveLightmapUV(bpy.types.Operator):
"""Remove Lightmap UV for selection"""
"""Remove Lightmap UV for set"""
bl_idname = "tlm.remove_uv_selection"
bl_label = "Remove Lightmap UV"
bl_description = "Remove Lightmap UV for selection"
bl_description = "Remove Lightmap UV for set"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
for obj in bpy.context.selected_objects:
if obj.type == "MESH":
uv_layers = obj.data.uv_layers
if bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Scene":
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
for uvlayer in uv_layers:
if uvlayer.name == "UVMap_Lightmap":
uv_layers.remove(uvlayer)
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"
for uvlayer in uv_layers:
if uvlayer.name == uv_channel:
uv_layers.remove(uvlayer)
elif bpy.context.scene.TLM_SceneProperties.tlm_utility_set == "Selection":
for obj in bpy.context.selected_objects:
if obj.type == "MESH":
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"
for uvlayer in uv_layers:
if uvlayer.name == uv_channel:
uv_layers.remove(uvlayer)
else: #Enabled
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
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"
for uvlayer in uv_layers:
if uvlayer.name == uv_channel:
uv_layers.remove(uvlayer)
return{'FINISHED'}
@ -222,8 +476,8 @@ class TLM_SelectLightmapped(bpy.types.Operator):
def execute(self, context):
for obj in bpy.data.objects:
if obj.type == "MESH":
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:
obj.select_set(True)
@ -278,7 +532,7 @@ class TLM_AtlastListDeleteItem(bpy.types.Operator):
list = scene.TLM_AtlasList
index = scene.TLM_AtlasListItem
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
atlasName = scene.TLM_AtlasList[index].name
@ -310,7 +564,7 @@ class TLM_PostAtlastListDeleteItem(bpy.types.Operator):
list = scene.TLM_PostAtlasList
index = scene.TLM_PostAtlasListItem
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
atlasName = scene.TLM_PostAtlasList[index].name
@ -437,7 +691,7 @@ class TLM_BuildEnvironmentProbes(bpy.types.Operator):
def invoke(self, context, event):
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
if obj.type == "LIGHT_PROBE":
if obj.data.type == "CUBEMAP":
@ -500,7 +754,7 @@ class TLM_BuildEnvironmentProbes(bpy.types.Operator):
cam.rotation_euler = positions[val]
filename = os.path.join(directory, val) + "_" + camobj_name + ".hdr"
bpy.data.scenes['Scene'].render.filepath = filename
bpy.context.scene.render.filepath = filename
print("Writing out: " + val)
bpy.ops.render.render(write_still=True)
@ -642,7 +896,7 @@ class TLM_BuildEnvironmentProbes(bpy.types.Operator):
subprocess.call([envpipe3], shell=True)
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
obj.select_set(False)
cam_obj.select_set(True)
@ -686,7 +940,92 @@ class TLM_MergeAdjacentActors(bpy.types.Operator):
scene = context.scene
return {'FINISHED'}
class TLM_PrepareUVMaps(bpy.types.Operator):
bl_idname = "tlm.prepare_uvmaps"
bl_label = "Prepare UV maps"
bl_description = "Prepare UV lightmaps for selected objects"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
return {'FINISHED'}
class TLM_LoadLightmaps(bpy.types.Operator):
bl_idname = "tlm.load_lightmaps"
bl_label = "Load Lightmaps"
bl_description = "Load lightmaps from selected folder"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
utility.transfer_load()
build.finish_assemble()
return {'FINISHED'}
class TLM_ToggleTexelDensity(bpy.types.Operator):
bl_idname = "tlm.toggle_texel_density"
bl_label = "Toggle Texel Density"
bl_description = "Toggle visualize lightmap texel density for selected objects"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
for obj in bpy.context.selected_objects:
if obj.type == "MESH":
uv_layers = obj.data.uv_layers
#if the object has a td_vis in the uv maps, toggle off
#else toggle on
if obj.TLM_ObjectProperties.tlm_use_default_channel:
for i in range(0, len(uv_layers)):
if uv_layers[i].name == 'UVMap_Lightmap':
uv_layers.active_index = i
break
else:
for i in range(0, len(uv_layers)):
if uv_layers[i].name == obj.TLM_ObjectProperties.tlm_uv_channel:
uv_layers.active_index = i
break
#filepath = r"C:\path\to\image.png"
#img = bpy.data.images.load(filepath)
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
space_data = area.spaces.active
bpy.ops.screen.area_dupli('INVOKE_DEFAULT')
new_window = context.window_manager.windows[-1]
area = new_window.screen.areas[-1]
area.type = 'VIEW_3D'
#bg = space_data.background_images.new()
print(bpy.context.object)
bpy.ops.object.bake_td_uv_to_vc()
#bg.image = img
break
#set active uv_layer to
print("TLM_Viz_Toggle")
return {'FINISHED'}
@ -698,7 +1037,4 @@ def TLM_HalfResolution():
pass
def TLM_DivideLMGroups():
pass
def TLM_LoadFromFolder():
pass

View file

@ -0,0 +1,66 @@
import bpy, os, math, importlib
from bpy.types import Menu, Operator, Panel, UIList
from bpy.props import (
StringProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
EnumProperty,
PointerProperty,
)
class TLM_PT_Imagetools(bpy.types.Panel):
bl_label = "TLM Imagetools"
bl_space_type = "IMAGE_EDITOR"
bl_region_type = 'UI'
bl_category = "TLM Imagetools"
def draw_header(self, _):
layout = self.layout
row = layout.row(align=True)
row.label(text ="Image Tools")
def draw(self, context):
layout = self.layout
activeImg = None
for area in bpy.context.screen.areas:
if area.type == 'IMAGE_EDITOR':
activeImg = area.spaces.active.image
if activeImg is not None and activeImg.name != "Render Result" and activeImg.name != "Viewer Node":
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
row = layout.row(align=True)
row.label(text ="OpenCV not installed.")
else:
row = layout.row(align=True)
row.label(text ="Method")
row = layout.row(align=True)
row.prop(activeImg.TLM_ImageProperties, "tlm_image_scale_engine")
row = layout.row(align=True)
row.prop(activeImg.TLM_ImageProperties, "tlm_image_cache_switch")
row = layout.row(align=True)
row.operator("tlm.image_upscale")
if activeImg.TLM_ImageProperties.tlm_image_cache_switch:
row = layout.row(align=True)
row.label(text ="Switch up.")
row = layout.row(align=True)
row.operator("tlm.image_downscale")
if activeImg.TLM_ImageProperties.tlm_image_cache_switch:
row = layout.row(align=True)
row.label(text ="Switch down.")
if activeImg.TLM_ImageProperties.tlm_image_scale_engine == "OpenCV":
row = layout.row(align=True)
row.prop(activeImg.TLM_ImageProperties, "tlm_image_scale_method")
else:
row = layout.row(align=True)
row.label(text ="Select an image")

View file

@ -0,0 +1,17 @@
import bpy
from bpy.props import *
from bpy.types import Menu, Panel
class TLM_PT_LightMenu(bpy.types.Panel):
bl_label = "The Lightmapper"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "light"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
scene = context.scene
obj = bpy.context.object
layout.use_property_split = True
layout.use_property_decorate = False

View file

@ -0,0 +1,118 @@
import bpy
from bpy.props import *
from bpy.types import Menu, Panel
class TLM_PT_ObjectMenu(bpy.types.Panel):
bl_label = "The Lightmapper"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
scene = context.scene
obj = bpy.context.object
layout.use_property_split = True
layout.use_property_decorate = False
if obj.type == "MESH":
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_use")
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_use_default_channel")
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
row = layout.row()
row.prop_search(obj.TLM_ObjectProperties, "tlm_uv_channel", obj.data, "uv_layers", text='UV Channel')
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_resolution")
if obj.TLM_ObjectProperties.tlm_use_default_channel:
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_unwrap_mode")
row = layout.row()
if obj.TLM_ObjectProperties.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(obj.TLM_ObjectProperties, "tlm_atlas_pointer", scene, "TLM_AtlasList", text='Atlas Group')
row = layout.row()
else:
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
row = layout.row()
else:
row = layout.row()
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()
item = scene.TLM_PostAtlasList[scene.TLM_PostAtlasListItem]
row.prop_search(obj.TLM_ObjectProperties, "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(obj.TLM_ObjectProperties, "tlm_mesh_unwrap_margin")
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filter_override")
row = layout.row()
if obj.TLM_ObjectProperties.tlm_mesh_filter_override:
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_mode")
row = layout.row(align=True)
if obj.TLM_ObjectProperties.tlm_mesh_filtering_mode == "Gaussian":
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_gaussian_strength")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
elif obj.TLM_ObjectProperties.tlm_mesh_filtering_mode == "Box":
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_box_strength")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
elif obj.TLM_ObjectProperties.tlm_mesh_filtering_mode == "Bilateral":
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_bilateral_diameter")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_bilateral_color_deviation")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_bilateral_coordinate_deviation")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
else:
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_median_kernel", expand=True)
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
class TLM_PT_MaterialMenu(bpy.types.Panel):
bl_label = "The Lightmapper"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "material"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
scene = context.scene
obj = bpy.context.object
layout.use_property_split = True
layout.use_property_decorate = False
mat = bpy.context.material
if mat == None:
return
if obj.type == "MESH":
row = layout.row()
row.prop(mat, "TLM_ignore")

View file

@ -0,0 +1,582 @@
import bpy, importlib, math
from bpy.props import *
from bpy.types import Menu, Panel
from .. utility import icon
from .. properties.denoiser import oidn, optix
class TLM_PT_Settings(bpy.types.Panel):
bl_label = "Settings"
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)
#We list LuxCoreRender as available, by default we assume Cycles exists
row.prop(sceneProperties, "tlm_lightmap_engine")
if sceneProperties.tlm_lightmap_engine == "Cycles":
#CYCLES SETTINGS HERE
engineProperties = scene.TLM_EngineProperties
row = layout.row(align=True)
row.label(text="General Settings")
row = layout.row(align=True)
row.operator("tlm.build_lightmaps")
row = layout.row(align=True)
row.operator("tlm.clean_lightmaps")
row = layout.row(align=True)
row.operator("tlm.explore_lightmaps")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_apply_on_unwrap")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_headless")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_alert_on_finish")
if sceneProperties.tlm_alert_on_finish:
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_alert_sound")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_verbose")
#row = layout.row(align=True)
#row.prop(sceneProperties, "tlm_compile_statistics")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_override_bg_color")
if sceneProperties.tlm_override_bg_color:
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_override_color")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_reset_uv")
row = layout.row(align=True)
try:
if bpy.context.scene["TLM_Buildstat"] is not None:
row.label(text="Last build completed in: " + str(bpy.context.scene["TLM_Buildstat"][0]))
except:
pass
row = layout.row(align=True)
row.label(text="Cycles Settings")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_quality")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_resolution_scale")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_bake_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_target")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_lighting_mode")
# if scene.TLM_EngineProperties.tlm_lighting_mode == "combinedao" or scene.TLM_EngineProperties.tlm_lighting_mode == "indirectao":
# row = layout.row(align=True)
# row.prop(engineProperties, "tlm_premultiply_ao")
if scene.TLM_EngineProperties.tlm_bake_mode == "Background":
row = layout.row(align=True)
row.label(text="Warning! Background mode is currently unstable", icon_value=2)
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_network_render")
if sceneProperties.tlm_network_render:
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_network_paths")
#row = layout.row(align=True)
#row.prop(sceneProperties, "tlm_network_dir")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_caching_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_directional_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_lightmap_savedir")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_dilation_margin")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_exposure_multiplier")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_setting_supersample")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_metallic_clamp")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_texture_interpolation")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_texture_extrapolation")
# elif sceneProperties.tlm_lightmap_engine == "LuxCoreRender":
# engineProperties = scene.TLM_Engine2Properties
# row = layout.row(align=True)
# row.prop(engineProperties, "tlm_luxcore_dir")
# row = layout.row(align=True)
# row.operator("tlm.build_lightmaps")
# #LUXCORE SETTINGS HERE
# #luxcore_available = False
# #Look for Luxcorerender in the renderengine classes
# # for engine in bpy.types.RenderEngine.__subclasses__():
# # if engine.bl_idname == "LUXCORE":
# # luxcore_available = True
# # break
# # row = layout.row(align=True)
# # if not luxcore_available:
# # row.label(text="Please install BlendLuxCore.")
# # else:
# # row.label(text="LuxCoreRender not yet available.")
elif sceneProperties.tlm_lightmap_engine == "OctaneRender":
engineProperties = scene.TLM_Engine3Properties
#LUXCORE SETTINGS HERE
octane_available = True
row = layout.row(align=True)
row.operator("tlm.build_lightmaps")
row = layout.row(align=True)
row.operator("tlm.clean_lightmaps")
row = layout.row(align=True)
row.operator("tlm.explore_lightmaps")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_verbose")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_lightmap_savedir")
row = layout.row(align=True)
class TLM_PT_Denoise(bpy.types.Panel):
bl_label = "Denoise"
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_header(self, context):
scene = context.scene
sceneProperties = scene.TLM_SceneProperties
self.layout.prop(sceneProperties, "tlm_denoise_use", text="")
def draw(self, context):
layout = self.layout
scene = context.scene
layout.use_property_split = True
layout.use_property_decorate = False
sceneProperties = scene.TLM_SceneProperties
layout.active = sceneProperties.tlm_denoise_use
row = layout.row(align=True)
#row.prop(sceneProperties, "tlm_denoiser", expand=True)
#row = layout.row(align=True)
row.prop(sceneProperties, "tlm_denoise_engine", expand=True)
row = layout.row(align=True)
if sceneProperties.tlm_denoise_engine == "Integrated":
row.label(text="No options for Integrated.")
elif sceneProperties.tlm_denoise_engine == "OIDN":
denoiseProperties = scene.TLM_OIDNEngineProperties
row.prop(denoiseProperties, "tlm_oidn_path")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_verbose")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_threads")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_maxmem")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_affinity")
# row = layout.row(align=True)
# row.prop(denoiseProperties, "tlm_denoise_ao")
elif sceneProperties.tlm_denoise_engine == "Optix":
denoiseProperties = scene.TLM_OptixEngineProperties
row.prop(denoiseProperties, "tlm_optix_path")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_optix_verbose")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_optix_maxmem")
#row = layout.row(align=True)
#row.prop(denoiseProperties, "tlm_denoise_ao")
class TLM_PT_Filtering(bpy.types.Panel):
bl_label = "Filtering"
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_header(self, context):
scene = context.scene
sceneProperties = scene.TLM_SceneProperties
self.layout.prop(sceneProperties, "tlm_filtering_use", text="")
def draw(self, context):
layout = self.layout
scene = context.scene
layout.use_property_split = True
layout.use_property_decorate = False
sceneProperties = scene.TLM_SceneProperties
layout.active = sceneProperties.tlm_filtering_use
#row = layout.row(align=True)
#row.label(text="TODO MAKE CHECK")
#row = layout.row(align=True)
#row.prop(sceneProperties, "tlm_filtering_engine", expand=True)
row = layout.row(align=True)
if sceneProperties.tlm_filtering_engine == "OpenCV":
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
row = layout.row(align=True)
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")
row = layout.row(align=True)
if scene.TLM_SceneProperties.tlm_filtering_mode == "Gaussian":
row.prop(scene.TLM_SceneProperties, "tlm_filtering_gaussian_strength")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Box":
row.prop(scene.TLM_SceneProperties, "tlm_filtering_box_strength")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Bilateral":
row.prop(scene.TLM_SceneProperties, "tlm_filtering_bilateral_diameter")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_bilateral_color_deviation")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_bilateral_coordinate_deviation")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
else:
row.prop(scene.TLM_SceneProperties, "tlm_filtering_median_kernel", expand=True)
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
else:
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_numpy_filtering_mode")
class TLM_PT_Encoding(bpy.types.Panel):
bl_label = "Encoding"
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_header(self, context):
scene = context.scene
sceneProperties = scene.TLM_SceneProperties
self.layout.prop(sceneProperties, "tlm_encoding_use", text="")
def draw(self, context):
layout = self.layout
scene = context.scene
layout.use_property_split = True
layout.use_property_decorate = False
sceneProperties = scene.TLM_SceneProperties
layout.active = sceneProperties.tlm_encoding_use
sceneProperties = scene.TLM_SceneProperties
row = layout.row(align=True)
if scene.TLM_EngineProperties.tlm_bake_mode == "Background":
row.label(text="Encoding options disabled in background mode")
row = layout.row(align=True)
else:
row.prop(sceneProperties, "tlm_encoding_device", expand=True)
row = layout.row(align=True)
if sceneProperties.tlm_encoding_device == "CPU":
row.prop(sceneProperties, "tlm_encoding_mode_a", expand=True)
else:
row.prop(sceneProperties, "tlm_encoding_mode_b", expand=True)
if sceneProperties.tlm_encoding_device == "CPU":
if sceneProperties.tlm_encoding_mode_a == "RGBM":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_encoding_range")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_decoder_setup")
if sceneProperties.tlm_encoding_mode_a == "RGBD":
pass
if sceneProperties.tlm_encoding_mode_a == "HDR":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_format")
else:
if sceneProperties.tlm_encoding_mode_b == "RGBM":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_encoding_range")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_decoder_setup")
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_encoding_mode_b == "HDR":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_format")
class TLM_PT_Utility(bpy.types.Panel):
bl_label = "Utilities"
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.label(text="Enable Lightmaps for set")
row = layout.row(align=True)
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.")
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.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")
class TLM_PT_Additional(bpy.types.Panel):
bl_label = "Additional"
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
sceneProperties = scene.TLM_SceneProperties
atlasListItem = scene.TLM_AtlasListItem
atlasList = scene.TLM_AtlasList
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)
if sceneProperties.tlm_atlas_mode == "Prepack":
rows = 2
if len(atlasList) > 1:
rows = 4
row = layout.row()
row.template_list("TLM_UL_AtlasList", "Atlas List", scene, "TLM_AtlasList", scene, "TLM_AtlasListItem", 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="")
if atlasListItem >= 0 and len(atlasList) > 0:
item = atlasList[atlasListItem]
layout.prop(item, "tlm_atlas_lightmap_unwrap_mode")
layout.prop(item, "tlm_atlas_lightmap_resolution")
layout.prop(item, "tlm_atlas_unwrap_margin")
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
layout.label(text="Objects: " + str(amount))
else:
layout.label(text="Postpacking is unstable.")
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
row = layout.row(align=True)
row.label(text="OpenCV is not installed. Install it through preferences.")
else:
rows = 2
if len(atlasList) > 1:
rows = 4
row = layout.row()
row.template_list("TLM_UL_PostAtlasList", "PostList", scene, "TLM_PostAtlasList", scene, "TLM_PostAtlasListItem", rows=rows)
col = row.column(align=True)
col.operator("tlm_postatlaslist.new_item", icon='ADD', text="")
col.operator("tlm_postatlaslist.delete_item", icon='REMOVE', text="")
if postatlasListItem >= 0 and len(postatlasList) > 0:
item = postatlasList[postatlasListItem]
layout.prop(item, "tlm_atlas_lightmap_resolution")
#Below list object counter
amount = 0
utilized = 0
atlasUsedArea = 0
atlasSize = item.tlm_atlas_lightmap_resolution
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_postpack_object:
if obj.TLM_ObjectProperties.tlm_postatlas_pointer == item.name:
amount = amount + 1
atlasUsedArea += int(obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution) ** 2
row = layout.row()
row.prop(item, "tlm_atlas_repack_on_cleanup")
#TODO SET A CHECK FOR THIS! ADD A CV2 CHECK TO UTILITY!
cv2 = True
if cv2:
row = layout.row()
row.prop(item, "tlm_atlas_dilation")
layout.label(text="Objects: " + str(amount))
utilized = atlasUsedArea / (int(atlasSize) ** 2)
layout.label(text="Utilized: " + str(utilized * 100) + "%")
if (utilized * 100) > 100:
layout.label(text="Warning! Overflow not yet supported")

View file

@ -0,0 +1,17 @@
import bpy
from bpy.props import *
from bpy.types import Menu, Panel
class TLM_PT_WorldMenu(bpy.types.Panel):
bl_label = "The Lightmapper"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "world"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
scene = context.scene
obj = bpy.context.object
layout.use_property_split = True
layout.use_property_decorate = False

View file

@ -0,0 +1,16 @@
import bpy
from bpy.utils import register_class, unregister_class
from . import addon_preferences
#from . import build, clean, explore, encode, installopencv
classes = [
addon_preferences.TLM_AddonPreferences
]
def register():
for cls in classes:
register_class(cls)
def unregister():
for cls in classes:
unregister_class(cls)

View file

@ -0,0 +1,75 @@
import bpy, platform
from os.path import basename, dirname
from bpy.types import AddonPreferences
from .. operators import installopencv
import importlib
class TLM_AddonPreferences(AddonPreferences):
bl_idname = "thelightmapper"
def draw(self, context):
layout = self.layout
box = layout.box()
row = box.row()
row.label(text="OpenCV")
cv2 = importlib.util.find_spec("cv2")
if cv2 is not None:
row.label(text="OpenCV installed")
else:
if platform.system() == "Windows":
row.label(text="OpenCV not found - Install as administrator!", icon_value=2)
else:
row.label(text="OpenCV not found - Click to install!", icon_value=2)
row = box.row()
row.operator("tlm.install_opencv_lightmaps", icon="PREFERENCES")
box = layout.box()
row = box.row()
row.label(text="Blender Xatlas")
if "blender_xatlas" in bpy.context.preferences.addons.keys():
row.label(text="Blender Xatlas installed and available")
else:
row.label(text="Blender Xatlas not installed", icon_value=2)
row = box.row()
row.label(text="Github: https://github.com/mattedicksoncom/blender-xatlas")
box = layout.box()
row = box.row()
row.label(text="RizomUV Bridge")
row.label(text="Coming soon")
box = layout.box()
row = box.row()
row.label(text="UVPackmaster")
row.label(text="Coming soon")
texel_density_addon = False
for addon in bpy.context.preferences.addons.keys():
if addon.startswith("Texel_Density"):
texel_density_addon = True
box = layout.box()
row = box.row()
row.label(text="Texel Density Checker")
if texel_density_addon:
row.label(text="Texel Density Checker installed and available")
else:
row.label(text="Texel Density Checker", icon_value=2)
row.label(text="Coming soon")
row = box.row()
row.label(text="Github: https://github.com/mrven/Blender-Texel-Density-Checker")
box = layout.box()
row = box.row()
row.label(text="LuxCoreRender")
row.label(text="Coming soon")
box = layout.box()
row = box.row()
row.label(text="OctaneRender")
row.label(text="Coming soon")

View file

@ -1,7 +1,7 @@
import bpy
from bpy.utils import register_class, unregister_class
from . import scene, object, atlas
from . renderer import cycles, luxcorerender
from . import scene, object, atlas, image
from . renderer import cycles, luxcorerender, octanerender
from . denoiser import oidn, optix
classes = [
@ -9,12 +9,14 @@ classes = [
object.TLM_ObjectProperties,
cycles.TLM_CyclesSceneProperties,
luxcorerender.TLM_LuxCoreSceneProperties,
octanerender.TLM_OctanerenderSceneProperties,
oidn.TLM_OIDNEngineProperties,
optix.TLM_OptixEngineProperties,
atlas.TLM_AtlasListItem,
atlas.TLM_UL_AtlasList,
atlas.TLM_PostAtlasListItem,
atlas.TLM_UL_PostAtlasList
atlas.TLM_UL_PostAtlasList,
image.TLM_ImageProperties
]
def register():
@ -25,12 +27,14 @@ def register():
bpy.types.Object.TLM_ObjectProperties = bpy.props.PointerProperty(type=object.TLM_ObjectProperties)
bpy.types.Scene.TLM_EngineProperties = bpy.props.PointerProperty(type=cycles.TLM_CyclesSceneProperties)
bpy.types.Scene.TLM_Engine2Properties = bpy.props.PointerProperty(type=luxcorerender.TLM_LuxCoreSceneProperties)
bpy.types.Scene.TLM_Engine3Properties = bpy.props.PointerProperty(type=octanerender.TLM_OctanerenderSceneProperties)
bpy.types.Scene.TLM_OIDNEngineProperties = bpy.props.PointerProperty(type=oidn.TLM_OIDNEngineProperties)
bpy.types.Scene.TLM_OptixEngineProperties = bpy.props.PointerProperty(type=optix.TLM_OptixEngineProperties)
bpy.types.Scene.TLM_AtlasListItem = bpy.props.IntProperty(name="Index for my_list", default=0)
bpy.types.Scene.TLM_AtlasList = bpy.props.CollectionProperty(type=atlas.TLM_AtlasListItem)
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.Material.TLM_ignore = bpy.props.BoolProperty(name="Skip material", description="Ignore material for lightmapped object", default=False)
@ -42,9 +46,11 @@ def unregister():
del bpy.types.Object.TLM_ObjectProperties
del bpy.types.Scene.TLM_EngineProperties
del bpy.types.Scene.TLM_Engine2Properties
del bpy.types.Scene.TLM_Engine3Properties
del bpy.types.Scene.TLM_OIDNEngineProperties
del bpy.types.Scene.TLM_OptixEngineProperties
del bpy.types.Scene.TLM_AtlasListItem
del bpy.types.Scene.TLM_AtlasList
del bpy.types.Scene.TLM_PostAtlasListItem
del bpy.types.Scene.TLM_PostAtlasList
del bpy.types.Scene.TLM_PostAtlasList
del bpy.types.Image.TLM_ImageProperties

View file

@ -34,12 +34,16 @@ class TLM_PostAtlasListItem(bpy.types.PropertyGroup):
max=1.0,
subtype='FACTOR')
tlm_atlas_lightmap_unwrap_mode : EnumProperty(
items = [('Lightmap', 'Lightmap', 'TODO'),
('SmartProject', 'Smart Project', 'TODO'),
('Xatlas', 'Xatlas', 'TODO')],
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'))
tlm_postatlas_lightmap_unwrap_mode : EnumProperty(
items = unwrap_modes,
name = "Unwrap Mode",
description="TODO",
description="Atlas unwrapping method",
default='SmartProject')
class TLM_UL_PostAtlasList(bpy.types.UIList):
@ -51,7 +55,7 @@ class TLM_UL_PostAtlasList(bpy.types.UIList):
#In list object counter
amount = 0
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_postpack_object:
if obj.TLM_ObjectProperties.tlm_postatlas_pointer == item.name:
@ -69,9 +73,6 @@ class TLM_UL_PostAtlasList(bpy.types.UIList):
layout.alignment = 'CENTER'
layout.label(text="", icon = custom_icon)
class TLM_AtlasListItem(bpy.types.PropertyGroup):
obj: PointerProperty(type=bpy.types.Object, description="The object to bake")
tlm_atlas_lightmap_resolution : EnumProperty(
@ -95,12 +96,17 @@ class TLM_AtlasListItem(bpy.types.PropertyGroup):
max=1.0,
subtype='FACTOR')
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'))
tlm_atlas_lightmap_unwrap_mode : EnumProperty(
items = [('Lightmap', 'Lightmap', 'TODO'),
('SmartProject', 'Smart Project', 'TODO'),
('Xatlas', 'Xatlas', 'TODO')],
items = unwrap_modes,
name = "Unwrap Mode",
description="TODO",
description="Atlas unwrapping method",
default='SmartProject')
class TLM_UL_AtlasList(bpy.types.UIList):
@ -111,7 +117,7 @@ class TLM_UL_AtlasList(bpy.types.UIList):
amount = 0
for obj in bpy.data.objects:
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:

View file

@ -1,10 +1,26 @@
import bpy
from bpy.props import *
class TLM_ObjectProperties(bpy.types.PropertyGroup):
tlm_image_scale_method : EnumProperty(
items = [('Native', 'Native', 'TODO'),
('OpenCV', 'OpenCV', 'TODO')],
class TLM_ImageProperties(bpy.types.PropertyGroup):
tlm_image_scale_engine : EnumProperty(
items = [('OpenCV', 'OpenCV', 'TODO')],
name = "Scaling engine",
description="TODO",
default='Native')
default='OpenCV')
#('Native', 'Native', 'TODO'),
tlm_image_scale_method : EnumProperty(
items = [('Nearest', 'Nearest', 'TODO'),
('Area', 'Area', 'TODO'),
('Linear', 'Linear', 'TODO'),
('Cubic', 'Cubic', 'TODO'),
('Lanczos', 'Lanczos', 'TODO')],
name = "Scaling method",
description="TODO",
default='Lanczos')
tlm_image_cache_switch : BoolProperty(
name="Cache for quickswitch",
description="Caches scaled images for quick switching",
default=True)

View file

@ -7,7 +7,7 @@ class TLM_ObjectProperties(bpy.types.PropertyGroup):
tlm_atlas_pointer : StringProperty(
name = "Atlas Group",
description = "Atlas Lightmap Group",
description = "",
default = "")
tlm_postatlas_pointer : StringProperty(
@ -51,8 +51,7 @@ class TLM_ObjectProperties(bpy.types.PropertyGroup):
unwrap_modes = [('Lightmap', 'Lightmap', 'TODO'),
('SmartProject', 'Smart Project', 'TODO'),
('CopyExisting', 'Copy Existing', 'TODO'),
('AtlasGroupA', 'Atlas Group (Prepack)', 'TODO')]
('AtlasGroupA', 'Atlas Group (Prepack)', 'Attaches the object to a prepack Atlas group. Will overwrite UV map on build.')]
tlm_postpack_object : BoolProperty( #CHECK INSTEAD OF ATLASGROUPB
name="Postpack object",
@ -145,4 +144,14 @@ class TLM_ObjectProperties(bpy.types.PropertyGroup):
name="Median kernel",
default=3,
min=1,
max=5)
max=5)
tlm_use_default_channel : BoolProperty(
name="Use default UV channel",
description="Will either use or create the default UV Channel 'UVMap_Lightmap' upon build.",
default=True)
tlm_uv_channel : StringProperty(
name = "UV Channel",
description = "Use any custom UV Channel for the lightmap",
default = "UVMap")

View file

@ -21,6 +21,16 @@ class TLM_CyclesSceneProperties(bpy.types.PropertyGroup):
description="Select baking quality",
default="0")
targets = [('texture', 'Image texture', 'Build to image texture')]
if (2, 92, 0) >= bpy.app.version:
targets.append(('vertex', 'Vertex colors', 'Build to vertex colors'))
tlm_target : EnumProperty(
items = targets,
name = "Build Target",
description="Select target to build to",
default="texture")
tlm_resolution_scale : EnumProperty(
items = [('1', '1/1', '1'),
('2', '1/2', '2'),
@ -45,10 +55,12 @@ class TLM_CyclesSceneProperties(bpy.types.PropertyGroup):
description="Select bake mode",
default="Foreground")
caching_modes = [('Copy', 'Copy', 'More overhead; allows for network.')]
#caching_modes.append(('Cache', 'Cache', 'Cache in separate blend'),('Node', 'Node restore', 'EXPERIMENTAL! Use with care'))
tlm_caching_mode : EnumProperty(
items = [('Copy', 'Copy', 'More overhead; allows for network.'),
('Cache', 'Cache', 'Cache in separate blend'),
('Node', 'Node restore', 'EXPERIMENTAL! Use with care')],
items = caching_modes,
name = "Caching mode",
description="Select cache mode",
default="Copy")
@ -88,8 +100,16 @@ class TLM_CyclesSceneProperties(bpy.types.PropertyGroup):
tlm_lighting_mode : EnumProperty(
items = [('combined', 'Combined', 'Bake combined lighting'),
('combinedao', 'Combined+AO', 'Bake combined lighting with Ambient Occlusion'),
('indirect', 'Indirect', 'Bake indirect lighting'),
('ao', 'AO', 'Bake only 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",
description="TODO.",
default="combined")
default="combined")
tlm_premultiply_ao : BoolProperty(
name="Premultiply AO",
description="Ambient Occlusion will be premultiplied together with lightmaps, requiring less textures.",
default=True)

View file

@ -0,0 +1,10 @@
import bpy
from bpy.props import *
class TLM_OctanerenderSceneProperties(bpy.types.PropertyGroup):
tlm_lightmap_savedir : StringProperty(
name="Lightmap Directory",
description="TODO",
default="Lightmaps",
subtype="FILE_PATH")

View file

@ -1,11 +1,19 @@
import bpy
import bpy, os
from bpy.props import *
from .. utility import utility
def transfer_load():
load_folder = 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)
class TLM_SceneProperties(bpy.types.PropertyGroup):
engines = [('Cycles', 'Cycles', 'Use Cycles for lightmapping')]
engines.append(('LuxCoreRender', 'LuxCoreRender', 'Use LuxCoreRender for lightmapping'))
#engines.append(('LuxCoreRender', 'LuxCoreRender', 'Use LuxCoreRender for lightmapping'))
#engines.append(('OctaneRender', 'Octane Render', 'Use Octane Render for lightmapping'))
tlm_atlas_pointer : StringProperty(
@ -112,7 +120,7 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
#FILTERING SETTINGS GROUP
tlm_filtering_use : BoolProperty(
name="Enable Filtering",
name="Enable denoising",
description="Enable denoising for lightmaps",
default=False)
@ -182,6 +190,17 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
min=1,
max=5)
tlm_clamp_hdr : BoolProperty(
name="Enable HDR Clamp",
description="Clamp HDR Value",
default=False)
tlm_clamp_hdr_value : IntProperty(
name="HDR Clamp value",
default=10,
min=0,
max=20)
#Encoding properties
tlm_encoding_use : BoolProperty(
name="Enable encoding",
@ -197,12 +216,13 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
encoding_modes_1 = [('RGBM', 'RGBM', '8-bit HDR encoding. Good for compatibility, good for memory but has banding issues.'),
('RGBD', 'RGBD', '8-bit HDR encoding. Similar to RGBM.'),
('HDR', 'HDR', '32-bit HDR encoding. Best quality, but high memory usage and not compatible with all devices.')]
('HDR', 'HDR', '32-bit HDR encoding. Best quality, but high memory usage and not compatible with all devices.'),
('SDR', 'SDR', '8-bit flat encoding.')]
encoding_modes_2 = [('RGBM', 'RGBM', '8-bit HDR encoding. Good for compatibility, good for memory but has banding issues.'),
('RGBD', 'RGBD', '8-bit HDR encoding. Similar to RGBM.'),
encoding_modes_2 = [('RGBD', 'RGBD', '8-bit HDR encoding. Similar to RGBM.'),
('LogLuv', 'LogLuv', '8-bit HDR encoding. Different.'),
('HDR', 'HDR', '32-bit HDR encoding. Best quality, but high memory usage and not compatible with all devices.')]
('HDR', 'HDR', '32-bit HDR encoding. Best quality, but high memory usage and not compatible with all devices.'),
('SDR', 'SDR', '8-bit flat encoding.')]
tlm_encoding_mode_a : EnumProperty(
items = encoding_modes_1,
@ -275,8 +295,7 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
tlm_mesh_lightmap_unwrap_mode : EnumProperty(
items = [('Lightmap', 'Lightmap', 'TODO'),
('SmartProject', 'Smart Project', 'TODO'),
('CopyExisting', 'Copy Existing', 'TODO'),
('AtlasGroupA', 'Atlas Group (Prepack)', 'TODO'),
('AtlasGroupA', 'Atlas Group (Prepack)', 'Attaches the object to a prepack Atlas group. Will overwrite UV map on build.'),
('Xatlas', 'Xatlas', 'TODO')],
name = "Unwrap Mode",
description="TODO",
@ -317,12 +336,30 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
tlm_metallic_clamp : EnumProperty(
items = [('ignore', 'Ignore', 'Ignore clamping'),
('skip', 'Skip', 'Skip baking metallic materials'),
('zero', 'Zero', 'Set zero'),
('limit', 'Limit', 'Clamp to 0.9')],
name = "Metallic clamping",
description="TODO.",
default="ignore")
tlm_texture_interpolation : EnumProperty(
items = [('Smart', 'Smart', 'Bicubic when magnifying.'),
('Cubic', 'Cubic', 'Cubic interpolation'),
('Closest', 'Closest', 'No interpolation'),
('Linear', 'Linear', 'Linear')],
name = "Texture interpolation",
description="Texture interpolation.",
default="Linear")
tlm_texture_extrapolation : EnumProperty(
items = [('REPEAT', 'Repeat', 'Repeat in both direction.'),
('EXTEND', 'Extend', 'Extend by repeating edge pixels.'),
('CLIP', 'Clip', 'Clip to image size')],
name = "Texture extrapolation",
description="Texture extrapolation.",
default="EXTEND")
tlm_verbose : BoolProperty(
name="Verbose",
description="Verbose console output",
@ -409,4 +446,52 @@ class TLM_SceneProperties(bpy.types.PropertyGroup):
('CYCLES', 'Cycles', 'TODO')],
name = "Probe Render Engine",
description="TODO",
default='BLENDER_EEVEE')
default='BLENDER_EEVEE')
tlm_load_folder : StringProperty(
name="Load Folder",
description="Load existing lightmaps from folder",
subtype="DIR_PATH")
tlm_utility_set : EnumProperty(
items = [('Scene', 'Scene', 'Set for all objects in the scene.'),
('Selection', 'Selection', 'Set for selected objects.'),
('Enabled', 'Enabled', 'Set for objects that has been enabled for lightmapping.')],
name = "Set",
description="Utility selection set",
default='Scene')
tlm_resolution_weight : EnumProperty(
items = [('Single', 'Single', 'Set a single resolution for all objects.'),
('Dimension', 'Dimension', 'Distribute resolutions based on object dimensions.'),
('Surface', 'Surface', 'Distribute resolutions based on mesh surface area.'),
('Volume', 'Volume', 'Distribute resolutions based on mesh volume.')],
name = "Resolution weight",
description="Method for setting resolution value",
default='Single')
#Todo add vertex color option
tlm_resolution_min : 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')],
name = "Minimum resolution",
description="Minimum distributed resolution",
default='32')
tlm_resolution_max : EnumProperty(
items = [('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO')],
name = "Maximum resolution",
description="Maximum distributed resolution",
default='256')

View file

@ -1,17 +1,20 @@
import bpy, os, subprocess, sys, platform, aud, json, datetime, socket
import threading
from . import encoding, pack
from . cycles import lightmap, prepare, nodes, cache
from . luxcore import setup
from . octane import configure, lightmap2
from . denoiser import integrated, oidn, optix
from . filtering import opencv
from . gui import Viewport
from .. network import client
from os import listdir
from os.path import isfile, join
from time import time, sleep
from importlib import util
previous_settings = {}
postprocess_shutdown = False
def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
@ -21,15 +24,31 @@ def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
print("Building lightmaps")
if bpy.context.scene.TLM_EngineProperties.tlm_lighting_mode == "combinedao":
scene = bpy.context.scene
if not "tlm_plus_mode" in bpy.app.driver_namespace or bpy.app.driver_namespace["tlm_plus_mode"] == 0:
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))
bpy.app.driver_namespace["tlm_plus_mode"] = 1
print("Plus Mode")
if bpy.context.scene.TLM_EngineProperties.tlm_bake_mode == "Foreground" or background_mode==True:
global start_time
start_time = time()
bpy.app.driver_namespace["tlm_start_time"] = time()
scene = bpy.context.scene
sceneProperties = scene.TLM_SceneProperties
#Timer start here bound to global
if not background_mode and bpy.context.scene.TLM_EngineProperties.tlm_lighting_mode != "combinedao":
#pass
setGui(1)
if check_save():
print("Please save your file first")
@ -52,12 +71,6 @@ def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
self.report({'INFO'}, "Error:Filtering - OpenCV not installed")
return{'FINISHED'}
#TODO DO some resolution change
#if checkAtlasSize():
# print("Error: AtlasGroup overflow")
# self.report({'INFO'}, "Error: AtlasGroup overflow - Too many objects")
# return{'FINISHED'}
setMode()
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
@ -67,19 +80,6 @@ def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
#Naming check
naming_check()
# if sceneProperties.tlm_reset_uv or sceneProperties.tlm_atlas_mode == "Postpack":
# for obj in bpy.data.objects:
# if obj.type == "MESH":
# uv_layers = obj.data.uv_layers
#for uvlayer in uv_layers:
# if uvlayer.name == "UVMap_Lightmap":
# uv_layers.remove(uvlayer)
## RENDER DEPENDENCY FROM HERE
if sceneProperties.tlm_lightmap_engine == "Cycles":
prepare.init(self, previous_settings)
@ -90,18 +90,14 @@ def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
if sceneProperties.tlm_lightmap_engine == "OctaneRender":
pass
#Renderer - Store settings
#Renderer - Set settings
#Renderer - Config objects, lights, world
configure.init(self, previous_settings)
begin_build()
else:
print("Baking in background")
filepath = bpy.data.filepath
bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath)
@ -111,22 +107,7 @@ def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
scene = bpy.context.scene
sceneProperties = scene.TLM_SceneProperties
#We dynamically load the renderer and denoiser, instead of loading something we don't use
if sceneProperties.tlm_lightmap_engine == "Cycles":
pass
if sceneProperties.tlm_lightmap_engine == "LuxCoreRender":
pass
if sceneProperties.tlm_lightmap_engine == "OctaneRender":
pass
#Timer start here bound to global
if check_save():
print("Please save your file first")
self.report({'INFO'}, "Please save your file first")
@ -168,23 +149,12 @@ def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
client.connect_client(HOST, PORT, bpy.data.filepath, 0)
# with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# s.connect((HOST, PORT))
# message = {
# "call" : 1,
# "command" : 1,
# "enquiry" : 0,
# "args" : bpy.data.filepath
# }
# s.sendall(json.dumps(message).encode())
# data = s.recv(1024)
# print(data.decode())
finish_assemble()
else:
print("Background driver process")
bpy.app.driver_namespace["alpha"] = 0
bpy.app.driver_namespace["tlm_process"] = False
@ -196,6 +166,8 @@ def prepare_build(self=0, background_mode=False, shutdown_after_build=False):
def distribute_building():
print("Distributing lightmap building")
#CHECK IF THERE'S AN EXISTING SUBPROCESS
if not os.path.isfile(os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir, "process.tlm")):
@ -215,8 +187,16 @@ def distribute_building():
with open(os.path.join(write_directory, "process.tlm"), 'w') as file:
json.dump(process_status, file, indent=2)
bpy.app.driver_namespace["tlm_process"] = subprocess.Popen([sys.executable,"-b", blendPath,"--python-expr",'import bpy; import thelightmapper; thelightmapper.addon.utility.build.prepare_build(0, True);'], shell=False, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
if (2, 91, 0) > bpy.app.version:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
bpy.app.driver_namespace["tlm_process"] = subprocess.Popen([sys.executable,"-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([sys.executable,"-b", blendPath,"--python-expr",'import bpy; import thelightmapper; thelightmapper.addon.utility.build.prepare_build(0, True);'], shell=False, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
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)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Started process: " + str(bpy.app.driver_namespace["tlm_process"]) + " at " + str(datetime.datetime.now()))
@ -269,6 +249,10 @@ def finish_assemble(self=0):
if sceneProperties.tlm_lightmap_engine == "OctaneRender":
pass
if not 'start_time' in globals():
global start_time
start_time = time()
manage_build(True)
def begin_build():
@ -288,7 +272,8 @@ def begin_build():
pass
if sceneProperties.tlm_lightmap_engine == "OctaneRender":
pass
lightmap2.bake()
#Denoiser
if sceneProperties.tlm_denoise_use:
@ -429,7 +414,7 @@ def begin_build():
print("Encoding:" + str(file))
encoding.encodeImageRGBMCPU(img, sceneProperties.tlm_encoding_range, dirpath, 0)
if sceneProperties.tlm_encoding_mode_b == "RGBD":
if sceneProperties.tlm_encoding_mode_a == "RGBD":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("ENCODING RGBD")
@ -455,6 +440,36 @@ def begin_build():
print("Encoding:" + str(file))
encoding.encodeImageRGBDCPU(img, sceneProperties.tlm_encoding_range, dirpath, 0)
if sceneProperties.tlm_encoding_mode_a == "SDR":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("EXR Format")
ren = bpy.context.scene.render
ren.image_settings.file_format = "PNG"
#ren.image_settings.exr_codec = "scene.TLM_SceneProperties.tlm_exr_codec"
end = "_baked"
baked_image_array = []
if sceneProperties.tlm_denoise_use:
end = "_denoised"
if sceneProperties.tlm_filtering_use:
end = "_filtered"
#For each image in folder ending in denoised/filtered
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))
img.save_render(img.filepath_raw[:-4] + ".png")
else:
if sceneProperties.tlm_encoding_mode_b == "HDR":
@ -562,6 +577,33 @@ def begin_build():
print("Encoding:" + str(file))
encoding.encodeImageRGBDGPU(img, sceneProperties.tlm_encoding_range, dirpath, 0)
if sceneProperties.tlm_encoding_mode_b == "PNG":
ren = bpy.context.scene.render
ren.image_settings.file_format = "PNG"
#ren.image_settings.exr_codec = "scene.TLM_SceneProperties.tlm_exr_codec"
end = "_baked"
baked_image_array = []
if sceneProperties.tlm_denoise_use:
end = "_denoised"
if sceneProperties.tlm_filtering_use:
end = "_filtered"
#For each image in folder ending in denoised/filtered
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))
img.save_render(img.filepath_raw[:-4] + ".png")
manage_build()
def manage_build(background_pass=False):
@ -610,6 +652,10 @@ def manage_build(background_pass=False):
formatEnc = "_encoded.png"
if sceneProperties.tlm_encoding_mode_a == "SDR":
formatEnc = ".png"
else:
print("GPU Encoding")
@ -632,6 +678,10 @@ def manage_build(background_pass=False):
formatEnc = "_encoded.png"
if sceneProperties.tlm_encoding_mode_b == "SDR":
formatEnc = ".png"
if not background_pass:
nodes.exchangeLightmapsToPostfix("_baked", end, formatEnc)
@ -653,13 +703,13 @@ def manage_build(background_pass=False):
filepath = bpy.data.filepath
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), scene.TLM_EngineProperties.tlm_lightmap_savedir)
for obj in bpy.data.objects:
if obj.type == "MESH":
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)
for obj in bpy.data.objects:
if obj.type == "MESH":
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_rename(obj)
@ -672,77 +722,181 @@ def manage_build(background_pass=False):
if "_Original" in mat.name:
bpy.data.materials.remove(mat)
for obj in bpy.data.objects:
if obj.type == "MESH":
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:
img_name = obj.name + '_baked'
Lightmapimage = bpy.data.images[img_name]
obj["Lightmap"] = Lightmapimage.filepath_raw
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
atlasName = obj.TLM_ObjectProperties.tlm_atlas_pointer
img_name = atlasName + '_baked'
Lightmapimage = bpy.data.images[img_name]
obj["Lightmap"] = Lightmapimage.filepath_raw
elif obj.TLM_ObjectProperties.tlm_postpack_object:
atlasName = obj.TLM_ObjectProperties.tlm_postatlas_pointer
img_name = atlasName + '_baked' + ".hdr"
Lightmapimage = bpy.data.images[img_name]
obj["Lightmap"] = Lightmapimage.filepath_raw
else:
img_name = obj.name + '_baked'
Lightmapimage = bpy.data.images[img_name]
obj["Lightmap"] = Lightmapimage.filepath_raw
for image in bpy.data.images:
if image.name.endswith("_baked"):
bpy.data.images.remove(image, do_unlink=True)
total_time = sec_to_hours((time() - start_time))
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(total_time)
if "tlm_plus_mode" in bpy.app.driver_namespace: #First DIR pass
bpy.context.scene["TLM_Buildstat"] = total_time
if bpy.app.driver_namespace["tlm_plus_mode"] == 1: #First DIR pass
reset_settings(previous_settings["settings"])
filepath = bpy.data.filepath
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), scene.TLM_EngineProperties.tlm_lightmap_savedir)
if sceneProperties.tlm_lightmap_engine == "LuxCoreRender":
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)
pass
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_rename(obj)
if sceneProperties.tlm_lightmap_engine == "OctaneRender":
for mat in bpy.data.materials:
if mat.users < 1:
bpy.data.materials.remove(mat)
pass
for mat in bpy.data.materials:
if mat.name.startswith("."):
if "_Original" in mat.name:
bpy.data.materials.remove(mat)
if bpy.context.scene.TLM_EngineProperties.tlm_bake_mode == "Background":
pass
for image in bpy.data.images:
if image.name.endswith("_baked"):
bpy.data.images.remove(image, do_unlink=True)
if scene.TLM_SceneProperties.tlm_alert_on_finish:
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
alertSelect = scene.TLM_SceneProperties.tlm_alert_sound
files = os.listdir(dirpath)
for index, file in enumerate(files):
filename = extension = os.path.splitext(file)[0]
extension = os.path.splitext(file)[1]
os.rename(os.path.join(dirpath, file), os.path.join(dirpath, filename + "_dir" + extension))
print("First DIR pass complete")
bpy.app.driver_namespace["tlm_plus_mode"] = 2
prepare_build(self=0, background_mode=False, shutdown_after_build=False)
if not background_pass and bpy.context.scene.TLM_EngineProperties.tlm_lighting_mode != "combinedao":
#pass
setGui(0)
elif bpy.app.driver_namespace["tlm_plus_mode"] == 2:
filepath = bpy.data.filepath
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
files = os.listdir(dirpath)
for index, file in enumerate(files):
filename = os.path.splitext(file)[0]
extension = os.path.splitext(file)[1]
if not filename.endswith("_dir"):
os.rename(os.path.join(dirpath, file), os.path.join(dirpath, filename + "_ao" + extension))
print("Second AO pass complete")
total_time = sec_to_hours((time() - start_time))
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(total_time)
bpy.context.scene["TLM_Buildstat"] = total_time
reset_settings(previous_settings["settings"])
bpy.app.driver_namespace["tlm_plus_mode"] = 0
if not background_pass:
#TODO CHANGE!
nodes.exchangeLightmapsToPostfix(end, end + "_dir", formatEnc)
nodes.applyAOPass()
if alertSelect == "dash":
soundfile = "dash.ogg"
elif alertSelect == "pingping":
soundfile = "pingping.ogg"
elif alertSelect == "gentle":
soundfile = "gentle.ogg"
else:
soundfile = "noot.ogg"
scriptDir = os.path.dirname(os.path.realpath(__file__))
sound_path = os.path.abspath(os.path.join(scriptDir, '..', 'assets/'+soundfile))
total_time = sec_to_hours((time() - start_time))
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(total_time)
device = aud.Device()
sound = aud.Sound.file(sound_path)
device.play(sound)
bpy.context.scene["TLM_Buildstat"] = total_time
print("Lightmap building finished")
reset_settings(previous_settings["settings"])
if bpy.app.background:
print("Lightmap building finished")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Writing background process report")
write_directory = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
if sceneProperties.tlm_lightmap_engine == "LuxCoreRender":
if os.path.exists(os.path.join(write_directory, "process.tlm")):
pass
process_status = json.loads(open(os.path.join(write_directory, "process.tlm")).read())
if sceneProperties.tlm_lightmap_engine == "OctaneRender":
process_status[1]["completed"] = True
pass
with open(os.path.join(write_directory, "process.tlm"), 'w') as file:
json.dump(process_status, file, indent=2)
if bpy.context.scene.TLM_EngineProperties.tlm_bake_mode == "Background":
pass
if postprocess_shutdown:
sys.exit()
if not background_pass and bpy.context.scene.TLM_EngineProperties.tlm_lighting_mode != "combinedao":
#pass
setGui(0)
if scene.TLM_SceneProperties.tlm_alert_on_finish:
alertSelect = scene.TLM_SceneProperties.tlm_alert_sound
if alertSelect == "dash":
soundfile = "dash.ogg"
elif alertSelect == "pingping":
soundfile = "pingping.ogg"
elif alertSelect == "gentle":
soundfile = "gentle.ogg"
else:
soundfile = "noot.ogg"
scriptDir = os.path.dirname(os.path.realpath(__file__))
sound_path = os.path.abspath(os.path.join(scriptDir, '..', 'assets/'+soundfile))
device = aud.Device()
sound = aud.Sound.file(sound_path)
device.play(sound)
if bpy.app.background:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Writing background process report")
write_directory = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
if os.path.exists(os.path.join(write_directory, "process.tlm")):
process_status = json.loads(open(os.path.join(write_directory, "process.tlm")).read())
process_status[1]["completed"] = True
with open(os.path.join(write_directory, "process.tlm"), 'w') as file:
json.dump(process_status, file, indent=2)
if postprocess_shutdown:
sys.exit()
#TODO - SET BELOW TO UTILITY
@ -770,9 +924,8 @@ def reset_settings(prev_settings):
def naming_check():
for obj in bpy.data.objects:
if obj.type == "MESH":
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:
@ -829,6 +982,9 @@ def check_save():
def check_denoiser():
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Checking denoiser path")
scene = bpy.context.scene
if scene.TLM_SceneProperties.tlm_denoise_use:
@ -847,8 +1003,8 @@ def check_denoiser():
return 0
def check_materials():
for obj in bpy.data.objects:
if obj.type == "MESH":
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
@ -868,15 +1024,39 @@ def check_materials():
def sec_to_hours(seconds):
a=str(seconds//3600)
b=str((seconds%3600)//60)
c=str((seconds%3600)%60)
c=str(round((seconds%3600)%60,1))
d=["{} hours {} mins {} seconds".format(a, b, c)]
return d
def setMode():
obj = bpy.context.scene.objects[0]
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.mode_set(mode='OBJECT')
#TODO Make some checks that returns to previous selection
def setGui(mode):
if mode == 0:
context = bpy.context
driver = bpy.app.driver_namespace
if "TLM_UI" in driver:
driver["TLM_UI"].remove_handle()
if mode == 1:
#bpy.context.area.tag_redraw()
context = bpy.context
driver = bpy.app.driver_namespace
driver["TLM_UI"] = Viewport.ViewportDraw(context, "Building Lightmaps")
bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
def checkAtlasSize():
overflow = False
@ -897,7 +1077,7 @@ def checkAtlasSize():
utilized = 0
atlasUsedArea = 0
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_postpack_object:
if obj.TLM_ObjectProperties.tlm_postatlas_pointer == atlas.name:
@ -912,4 +1092,5 @@ def checkAtlasSize():
if overflow == True:
return True
else:
return False
return False

View file

@ -2,7 +2,6 @@ import bpy
#Todo - Check if already exists, in case multiple objects has the same material
def backup_material_copy(slot):
material = slot.material
dup = material.copy()
@ -16,25 +15,49 @@ def backup_material_cache_restore(slot, path):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Restore cache")
def backup_material_rename(obj):
if "TLM_PrevMatArray" in obj:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Renaming material for: " + obj.name)
# def backup_material_restore(obj): #??
# if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
# print("Restoring material for: " + obj.name)
for slot in obj.material_slots:
#Check if object has TLM_PrevMatArray
# if yes
# - check if array.len is bigger than 0:
# if yes:
# for slot in object:
# originalMaterial = TLM_PrevMatArray[index]
#
#
# if no:
# - In which cases are these?
if slot.material is not None:
if slot.material.name.endswith("_Original"):
newname = slot.material.name[1:-9]
if newname in bpy.data.materials:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Removing material: " + bpy.data.materials[newname].name)
bpy.data.materials.remove(bpy.data.materials[newname])
slot.material.name = newname
# if no:
# - In which cases are there not?
# - If a lightmapped material was applied to a non-lightmap object?
del obj["TLM_PrevMatArray"]
def backup_material_restore(obj):
# if bpy.data.materials[originalMaterial].users > 0: #TODO - Check if all lightmapped
# print("Material has multiple users")
# if originalMaterial in bpy.data.materials:
# slot.material = bpy.data.materials[originalMaterial]
# slot.material.use_fake_user = False
# elif "." + originalMaterial + "_Original" in bpy.data.materials:
# slot.material = bpy.data.materials["." + originalMaterial + "_Original"]
# slot.material.use_fake_user = False
# else:
# print("Material has one user")
# if "." + originalMaterial + "_Original" in bpy.data.materials:
# slot.material = bpy.data.materials["." + originalMaterial + "_Original"]
# slot.material.use_fake_user = False
# elif originalMaterial in bpy.data.materials:
# slot.material = bpy.data.materials[originalMaterial]
# slot.material.use_fake_user = False
def backup_material_restore(obj): #??
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Restoring material for: " + obj.name)
@ -59,9 +82,43 @@ def backup_material_restore(obj):
originalMaterial = ""
if slot.material is not None:
#slot.material.user_clear() Seems to be bad; See: https://developer.blender.org/T49837
bpy.data.materials.remove(slot.material)
#if slot.material.users < 2:
#slot.material.user_clear() #Seems to be bad; See: https://developer.blender.org/T49837
#bpy.data.materials.remove(slot.material)
if "." + originalMaterial + "_Original" in bpy.data.materials:
slot.material = bpy.data.materials["." + originalMaterial + "_Original"]
slot.material.use_fake_user = False
slot.material.use_fake_user = False
else:
print("No previous material for " + obj.name)
else:
print("No previous material for " + obj.name)
def backup_material_rename(obj): #??
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Renaming material for: " + obj.name)
if "TLM_PrevMatArray" in obj:
for slot in obj.material_slots:
if slot.material is not None:
if slot.material.name.endswith("_Original"):
newname = slot.material.name[1:-9]
if newname in bpy.data.materials:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Removing material: " + bpy.data.materials[newname].name)
#if bpy.data.materials[newname].users < 2:
#bpy.data.materials.remove(bpy.data.materials[newname]) #TODO - Maybe remove this
slot.material.name = newname
del obj["TLM_PrevMatArray"]
else:
print("No Previous material array for: " + obj.name)

View file

@ -1,25 +1,26 @@
import bpy, os
from .. import build
from time import time, sleep
def bake():
def bake(plus_pass=0):
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(False)
iterNum = 0
currentIterNum = 0
for obj in bpy.data.objects:
if obj.type == "MESH":
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
if iterNum > 1:
iterNum = iterNum - 1
for obj in bpy.data.objects:
if obj.type == 'MESH':
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:
scene = bpy.context.scene
@ -32,19 +33,45 @@ def bake():
obj.hide_render = False
scene.render.bake.use_clear = False
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Baking " + str(currentIterNum) + "/" + str(iterNum) + " (" + str(round(currentIterNum/iterNum*100, 2)) + "%) : " + obj.name)
#os.system("cls")
if scene.TLM_EngineProperties.tlm_lighting_mode == "combined" or scene.TLM_EngineProperties.tlm_lighting_mode == "combinedAO":
#if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Baking " + str(currentIterNum) + "/" + str(iterNum) + " (" + str(round(currentIterNum/iterNum*100, 2)) + "%) : " + obj.name)
#elapsed = build.sec_to_hours((time() - bpy.app.driver_namespace["tlm_start_time"]))
#print("Baked: " + str(currentIterNum) + " | Left: " + str(iterNum-currentIterNum))
elapsedSeconds = time() - bpy.app.driver_namespace["tlm_start_time"]
bakedObjects = currentIterNum
bakedLeft = iterNum-currentIterNum
if bakedObjects == 0:
bakedObjects = 1
averagePrBake = elapsedSeconds / bakedObjects
remaining = averagePrBake * bakedLeft
#print(time() - bpy.app.driver_namespace["tlm_start_time"])
print("Elapsed time: " + str(round(elapsedSeconds, 2)) + "s | ETA remaining: " + str(round(remaining, 2)) + "s") #str(elapsed[0])
#print("Averaged: " + str(averagePrBake))
#print("Remaining: " + str(remaining))
if scene.TLM_EngineProperties.tlm_target == "vertex":
scene.render.bake_target = "VERTEX_COLORS"
if scene.TLM_EngineProperties.tlm_lighting_mode == "combined":
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" or scene.TLM_EngineProperties.tlm_lighting_mode == "indirectAO":
elif scene.TLM_EngineProperties.tlm_lighting_mode == "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":
bpy.ops.object.bake(type="AO", margin=scene.TLM_EngineProperties.tlm_dilation_margin, use_clear=False)
elif scene.TLM_EngineProperties.tlm_lighting_mode == "combinedao":
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)
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)
bpy.ops.object.select_all(action='DESELECT')
currentIterNum = currentIterNum + 1

View file

@ -1,8 +1,8 @@
import bpy, os
def apply_lightmaps():
for obj in bpy.data.objects:
if obj.type == "MESH":
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
@ -32,8 +32,12 @@ def apply_lightmaps():
def apply_materials():
for obj in bpy.data.objects:
if obj.type == "MESH":
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
@ -90,7 +94,7 @@ def apply_materials():
for node in nodes:
if node.name == "Baked Image":
lightmapNode = node
lightmapNode.location = -800, 300
lightmapNode.location = -1200, 300
lightmapNode.name = "TLM_Lightmap"
foundBakedNode = True
@ -98,9 +102,10 @@ def apply_materials():
if not foundBakedNode:
lightmapNode = node_tree.nodes.new(type="ShaderNodeTexImage")
lightmapNode.location = -300, 300
lightmapNode.location = -1200, 300
lightmapNode.name = "TLM_Lightmap"
lightmapNode.interpolation = "Smart"
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"]
@ -118,37 +123,32 @@ def apply_materials():
#Find mainnode
mainNode = outputNode.inputs[0].links[0].from_node
#Clamp metallic
# if scene.TLM_SceneProperties.tlm_metallic_clamp != "ignore":
# if mainNode.type == "BSDF_PRINCIPLED":
# if len(mainNode.inputs[4].links) == 0:
# if scene.TLM_SceneProperties.tlm_metallic_clamp == "zero":
# mainNode.inputs[4].default_value = 0.0
# else:
# mainNode.inputs[4].default_value = 0.99
# else:
# pass
#Add all nodes first
#Add lightmap multipliction texture
mixNode = node_tree.nodes.new(type="ShaderNodeMixRGB")
mixNode.name = "Lightmap_Multiplication"
mixNode.location = -300, 300
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'
mixNode.inputs[0].default_value = 1.0
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")
UVLightmap.uv_map = "UVMap_Lightmap"
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 = -1000, 300
UVLightmap.location = -1500, 300
if(scene.TLM_SceneProperties.tlm_decoder_setup):
if scene.TLM_SceneProperties.tlm_encoding_device == "CPU":
@ -196,7 +196,7 @@ def apply_materials():
baseColorValue = mainNode.inputs[0].default_value
baseColorNode = node_tree.nodes.new(type="ShaderNodeRGB")
baseColorNode.outputs[0].default_value = baseColorValue
baseColorNode.location = ((mainNode.location[0] - 500, mainNode.location[1] - 300))
baseColorNode.location = ((mainNode.location[0] - 1100, mainNode.location[1] - 300))
baseColorNode.name = "Lightmap_BasecolorNode_A"
else:
baseColorNode = mainNode.inputs[0].links[0].from_node
@ -235,13 +235,19 @@ def apply_materials():
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"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(ext_postfix, new_postfix, formatHDR)
for obj in bpy.data.objects:
if obj.type == "MESH":
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
@ -267,6 +273,53 @@ def exchangeLightmapsToPostfix(ext_postfix, new_postfix, formatHDR=".hdr"):
for image in bpy.data.images:
image.reload()
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":
filepath = bpy.data.filepath
dirpath = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
LightmapPath = node.image.filepath_raw
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)
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):
scriptDir = os.path.dirname(os.path.realpath(__file__))

View file

@ -1,4 +1,4 @@
import bpy
import bpy, math
from . import cache
from .. utility import *
@ -31,13 +31,16 @@ def configure_lights():
def configure_meshes(self):
for obj in bpy.data.objects:
if obj.type == "MESH":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Configuring meshes")
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)
for obj in bpy.data.objects:
if obj.type == "MESH":
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_rename(obj)
@ -59,9 +62,18 @@ def configure_meshes(self):
scene = bpy.context.scene
for obj in bpy.data.objects:
if obj.type == "MESH":
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:
if scene.TLM_SceneProperties.tlm_apply_on_unwrap:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Applying transform to: " + obj.name)
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
obj.hide_select = False #Remember to toggle this back
for slot in obj.material_slots:
if "." + slot.name + '_Original' in bpy.data.materials:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
@ -77,33 +89,35 @@ def configure_meshes(self):
bpy.ops.object.select_all(action='DESELECT')
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
uv_layers = obj.data.uv_layers
if not "UVMap_Lightmap" in 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("UVMap made A")
uvmap = uv_layers.new(name="UVMap_Lightmap")
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 found...skipping")
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
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Lightmap shift A")
break
atlas_items.append(obj)
obj.select_set(True)
if scene.TLM_SceneProperties.tlm_apply_on_unwrap:
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
if atlasgroup.tlm_atlas_lightmap_unwrap_mode == "SmartProject":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Smart Project A for: " + str(atlas_items))
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)
@ -112,7 +126,12 @@ def configure_meshes(self):
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.smart_project(angle_limit=45.0, island_margin=atlasgroup.tlm_atlas_unwrap_margin, user_area_weight=1.0, use_aspect=True, stretch_to_bounds=False)
#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":
@ -123,8 +142,9 @@ def configure_meshes(self):
bpy.ops.object.mode_set(mode='OBJECT')
elif atlasgroup.tlm_atlas_lightmap_unwrap_mode == "Xatlas":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Temporary skip: COPYING SMART PROJECT")
print("Using Xatlas on Atlas Group: " + atlas)
for obj in atlas_items:
obj.select_set(True)
@ -139,176 +159,213 @@ def configure_meshes(self):
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Copied Existing A")
print("Copied Existing UV Map for Atlas Group: " + atlas)
for obj in bpy.data.objects:
if obj.type == "MESH":
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
for obj in bpy.data.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
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:
objWasHidden = False
objWasHidden = False
#For some reason, a Blender bug might prevent invisible objects from being smart projected
#We will turn the object temporarily visible
obj.hide_viewport = False
obj.hide_set(False)
#For some reason, a Blender bug might prevent invisible objects from being smart projected
#We will turn the object temporarily visible
obj.hide_viewport = False
obj.hide_set(False)
currentIterNum = currentIterNum + 1
currentIterNum = currentIterNum + 1
#Configure selection
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
obs = bpy.context.view_layer.objects
active = obs.active
#Configure selection
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
#Provide material if none exists
preprocess_material(obj, scene)
obs = bpy.context.view_layer.objects
active = obs.active
#UV Layer management here
if not obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
uv_layers = obj.data.uv_layers
if not "UVMap_Lightmap" in uv_layers:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("UVMap made B")
uvmap = uv_layers.new(name="UVMap_Lightmap")
uv_layers.active_index = len(uv_layers) - 1
#Provide material if none exists
preprocess_material(obj, scene)
#If lightmap
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "Lightmap":
if scene.TLM_SceneProperties.tlm_apply_on_unwrap:
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
bpy.ops.uv.lightmap_pack('EXEC_SCREEN', PREF_CONTEXT='ALL_FACES', PREF_MARGIN_DIV=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin)
#If smart project
elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "SmartProject":
#UV Layer management here
if not obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
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("Smart Project B")
if scene.TLM_SceneProperties.tlm_apply_on_unwrap:
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
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)
elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "Xatlas":
print("UV map created for obj: " + obj.name)
uvmap = uv_layers.new(name=uv_channel)
uv_layers.active_index = len(uv_layers) - 1
if scene.TLM_SceneProperties.tlm_apply_on_unwrap:
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
#If lightmap
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "Lightmap":
bpy.ops.uv.lightmap_pack('EXEC_SCREEN', PREF_CONTEXT='ALL_FACES', PREF_MARGIN_DIV=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin)
#import blender_xatlas
#blender_xatlas.Unwrap_Lightmap_Group_Xatlas_2(bpy.context)
#If smart project
elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "SmartProject":
#bpy.ops.object.setup_unwrap()
Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj)
elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("ATLAS GROUP: " + obj.TLM_ObjectProperties.tlm_atlas_pointer)
else: #if copy existing
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Copied Existing B")
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Existing found...skipping")
for i in range(0, len(uv_layers)):
if uv_layers[i].name == 'UVMap_Lightmap':
uv_layers.active_index = i
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Lightmap shift B")
break
print("Smart Project B")
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
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 obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "Xatlas":
Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj)
#Sort out nodes
for slot in obj.material_slots:
elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
nodetree = slot.material.node_tree
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("ATLAS GROUP: " + obj.TLM_ObjectProperties.tlm_atlas_pointer)
else: #if copy existing
outputNode = nodetree.nodes[0] #Presumed to be material output node
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Copied Existing UV Map for object: " + obj.name)
if(outputNode.type != "OUTPUT_MATERIAL"):
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Existing UV map found for obj: " + obj.name)
for i in range(0, len(uv_layers)):
if uv_layers[i].name == uv_channel:
uv_layers.active_index = i
break
#print(x)
#Sort out nodes
for slot in obj.material_slots:
nodetree = slot.material.node_tree
outputNode = nodetree.nodes[0] #Presumed to be material output node
if(outputNode.type != "OUTPUT_MATERIAL"):
for node in nodetree.nodes:
if node.type == "OUTPUT_MATERIAL":
outputNode = node
break
mainNode = outputNode.inputs[0].links[0].from_node
if mainNode.type not in ['BSDF_PRINCIPLED','BSDF_DIFFUSE','GROUP']:
#TODO! FIND THE PRINCIPLED PBR
self.report({'INFO'}, "The primary material node is not supported. Seeking first principled.")
if len(find_node_by_type(nodetree.nodes, Node_Types.pbr_node)) > 0:
mainNode = find_node_by_type(nodetree.nodes, Node_Types.pbr_node)[0]
else:
self.report({'INFO'}, "No principled found. Seeking diffuse")
if len(find_node_by_type(nodetree.nodes, Node_Types.diffuse)) > 0:
mainNode = find_node_by_type(nodetree.nodes, Node_Types.diffuse)[0]
else:
self.report({'INFO'}, "No supported nodes. Continuing anyway.")
if mainNode.type == 'GROUP':
if mainNode.node_tree != "Armory PBR":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("The material group is not supported!")
if (mainNode.type == "BSDF_PRINCIPLED"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("BSDF_Principled")
if scene.TLM_EngineProperties.tlm_directional_mode == "None":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Directional mode")
if not len(mainNode.inputs[19].links) == 0:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("NOT LEN 0")
ninput = mainNode.inputs[19].links[0]
noutput = mainNode.inputs[19].links[0].from_node
nodetree.links.remove(noutput.outputs[0].links[0])
#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
MetClampNode = nodes.new('ShaderNodeClamp')
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
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
MetClampNode = nodes.new('ShaderNodeClamp')
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
else:
mainNode.inputs[4].default_value = 0.0
if (mainNode.type == "BSDF_DIFFUSE"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("BSDF_Diffuse")
# if (mainNode.type == "BSDF_DIFFUSE"):
# if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
# print("BSDF_Diffuse")
#TODO FIX THIS PART!
#THIS IS USED IN CASES WHERE FOR SOME REASON THE USER FORGETS TO CONNECT SOMETHING INTO THE OUTPUT MATERIAL
for slot in obj.material_slots:
nodetree = bpy.data.materials[slot.name].node_tree
nodes = nodetree.nodes
#First search to get the first output material type
for node in nodetree.nodes:
if node.type == "OUTPUT_MATERIAL":
outputNode = node
mainNode = node
break
mainNode = outputNode.inputs[0].links[0].from_node
#Fallback to get search
if not mainNode.type == "OUTPUT_MATERIAL":
mainNode = nodetree.nodes.get("Material Output")
if mainNode.type not in ['BSDF_PRINCIPLED','BSDF_DIFFUSE','GROUP']:
#Last resort to first node in list
if not mainNode.type == "OUTPUT_MATERIAL":
mainNode = nodetree.nodes[0].inputs[0].links[0].from_node
#TODO! FIND THE PRINCIPLED PBR
self.report({'INFO'}, "The primary material node is not supported. Seeking first principled.")
# for node in nodes:
# if "LM" in node.name:
# nodetree.links.new(node.outputs[0], mainNode.inputs[0])
if len(find_node_by_type(nodetree.nodes, Node_Types.pbr_node)) > 0:
mainNode = find_node_by_type(nodetree.nodes, Node_Types.pbr_node)[0]
else:
self.report({'INFO'}, "No principled found. Seeking diffuse")
if len(find_node_by_type(nodetree.nodes, Node_Types.diffuse)) > 0:
mainNode = find_node_by_type(nodetree.nodes, Node_Types.diffuse)[0]
else:
self.report({'INFO'}, "No supported nodes. Continuing anyway.")
if mainNode.type == 'GROUP':
if mainNode.node_tree != "Armory PBR":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("The material group is not supported!")
if (mainNode.type == "BSDF_PRINCIPLED"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("BSDF_Principled")
if scene.TLM_EngineProperties.tlm_directional_mode == "None":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Directional mode")
if not len(mainNode.inputs[19].links) == 0:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("NOT LEN 0")
ninput = mainNode.inputs[19].links[0]
noutput = mainNode.inputs[19].links[0].from_node
nodetree.links.remove(noutput.outputs[0].links[0])
#Clamp metallic
if(mainNode.inputs[4].default_value == 1):
mainNode.inputs[4].default_value = 0.0
if (mainNode.type == "BSDF_DIFFUSE"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("BSDF_Diffuse")
for slot in obj.material_slots:
nodetree = bpy.data.materials[slot.name].node_tree
nodes = nodetree.nodes
#First search to get the first output material type
for node in nodetree.nodes:
if node.type == "OUTPUT_MATERIAL":
mainNode = node
break
#Fallback to get search
if not mainNode.type == "OUTPUT_MATERIAL":
mainNode = nodetree.nodes.get("Material Output")
#Last resort to first node in list
if not mainNode.type == "OUTPUT_MATERIAL":
mainNode = nodetree.nodes[0].inputs[0].links[0].from_node
for node in nodes:
if "LM" in node.name:
nodetree.links.new(node.outputs[0], mainNode.inputs[0])
for node in nodes:
if "Lightmap" in node.name:
nodes.remove(node)
# for node in nodes:
# if "Lightmap" in node.name:
# nodes.remove(node)
def preprocess_material(obj, scene):
if len(obj.material_slots) == 0:
@ -537,7 +594,7 @@ def store_existing(prev_container):
selected = []
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
if obj.select_get():
selected.append(obj.name)

View file

@ -22,7 +22,7 @@ class TLM_Integrated_Denoise:
bpy.ops.object.camera_add()
#Just select the first camera we find, needed for the compositor
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
if obj.type == "CAMERA":
bpy.context.scene.camera = obj
return

View file

@ -332,6 +332,205 @@ def encodeImageRGBDGPU(image, maxRange, outDir, quality):
#Todo - Find a way to save
#bpy.ops.image.save_all_modified()
#TODO - FINISH THIS
def encodeImageRGBMGPU(image, maxRange, outDir, quality):
input_image = bpy.data.images[image.name]
image_name = input_image.name
offscreen = gpu.types.GPUOffScreen(input_image.size[0], input_image.size[1])
image = input_image
vertex_shader = '''
uniform mat4 ModelViewProjectionMatrix;
in vec2 texCoord;
in vec2 pos;
out vec2 texCoord_interp;
void main()
{
//gl_Position = ModelViewProjectionMatrix * vec4(pos.xy, 0.0f, 1.0f);
//gl_Position.z = 1.0;
gl_Position = vec4(pos.xy, 100, 100);
texCoord_interp = texCoord;
}
'''
fragment_shader = '''
in vec2 texCoord_interp;
out vec4 fragColor;
uniform sampler2D image;
//Code from here: https://github.com/BabylonJS/Babylon.js/blob/master/src/Shaders/ShadersInclude/helperFunctions.fx
const float PI = 3.1415926535897932384626433832795;
const float HALF_MIN = 5.96046448e-08; // Smallest positive half.
const float LinearEncodePowerApprox = 2.2;
const float GammaEncodePowerApprox = 1.0 / LinearEncodePowerApprox;
const vec3 LuminanceEncodeApprox = vec3(0.2126, 0.7152, 0.0722);
const float Epsilon = 0.0000001;
#define saturate(x) clamp(x, 0.0, 1.0)
float maxEps(float x) {
return max(x, Epsilon);
}
float toLinearSpace(float color)
{
return pow(color, LinearEncodePowerApprox);
}
vec3 toLinearSpace(vec3 color)
{
return pow(color, vec3(LinearEncodePowerApprox));
}
vec4 toLinearSpace(vec4 color)
{
return vec4(pow(color.rgb, vec3(LinearEncodePowerApprox)), color.a);
}
vec3 toGammaSpace(vec3 color)
{
return pow(color, vec3(GammaEncodePowerApprox));
}
vec4 toGammaSpace(vec4 color)
{
return vec4(pow(color.rgb, vec3(GammaEncodePowerApprox)), color.a);
}
float toGammaSpace(float color)
{
return pow(color, GammaEncodePowerApprox);
}
float square(float value)
{
return value * value;
}
// Check if configurable value is needed.
const float rgbdMaxRange = 255.0;
vec4 toRGBM(vec3 color) {
vec4 rgbm;
color *= 1.0/6.0;
rgbm.a = saturate( max( max( color.r, color.g ), max( color.b, 1e-6 ) ) );
rgbm.a = clamp(floor(D) / 255.0, 0., 1.);
rgbm.rgb = color / rgbm.a;
return
float maxRGB = maxEps(max(color.r, max(color.g, color.b)));
float D = max(rgbdMaxRange / maxRGB, 1.);
D = clamp(floor(D) / 255.0, 0., 1.);
vec3 rgb = color.rgb * D;
// Helps with png quantization.
rgb = toGammaSpace(rgb);
return vec4(rgb, D);
}
vec3 fromRGBD(vec4 rgbd) {
// Helps with png quantization.
rgbd.rgb = toLinearSpace(rgbd.rgb);
// return rgbd.rgb * ((rgbdMaxRange / 255.0) / rgbd.a);
return rgbd.rgb / rgbd.a;
}
void main()
{
fragColor = toRGBM(texture(image, texCoord_interp).rgb);
}
'''
x_screen = 0
off_x = -100
off_y = -100
y_screen_flip = 0
sx = 200
sy = 200
vertices = (
(x_screen + off_x, y_screen_flip - off_y),
(x_screen + off_x, y_screen_flip - sy - off_y),
(x_screen + off_x + sx, y_screen_flip - sy - off_y),
(x_screen + off_x + sx, y_screen_flip - off_x))
if input_image.colorspace_settings.name != 'Linear':
input_image.colorspace_settings.name = 'Linear'
# Removing .exr or .hdr prefix
if image_name[-4:] == '.exr' or image_name[-4:] == '.hdr':
image_name = image_name[:-4]
target_image = bpy.data.images.get(image_name + '_encoded')
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(image_name + '_encoded')
if not target_image:
target_image = bpy.data.images.new(
name = image_name + '_encoded',
width = input_image.size[0],
height = input_image.size[1],
alpha = True,
float_buffer = False
)
shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
batch = batch_for_shader(
shader, 'TRI_FAN',
{
"pos": vertices,
"texCoord": ((0, 1), (0, 0), (1, 0), (1, 1)),
},
)
if image.gl_load():
raise Exception()
with offscreen.bind():
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)
shader.bind()
shader.uniform_int("image", 0)
batch.draw(shader)
buffer = bgl.Buffer(bgl.GL_BYTE, input_image.size[0] * input_image.size[1] * 4)
bgl.glReadBuffer(bgl.GL_BACK)
bgl.glReadPixels(0, 0, input_image.size[0], input_image.size[1], bgl.GL_RGBA, bgl.GL_UNSIGNED_BYTE, buffer)
offscreen.free()
target_image.pixels = [v / 255 for v in buffer]
input_image = target_image
#Save LogLuv
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(input_image.name)
input_image.filepath_raw = outDir + "/" + input_image.name + ".png"
#input_image.filepath_raw = outDir + "_encoded.png"
input_image.file_format = "PNG"
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 encodeImageRGBMCPU(image, maxRange, outDir, quality):
input_image = bpy.data.images[image.name]
image_name = input_image.name
@ -431,21 +630,6 @@ def encodeImageRGBDCPU(image, maxRange, outDir, quality):
result_pixel[i+1] = math.pow(result_pixel[i+1] * D, 1/2.2)
result_pixel[i+2] = math.pow(result_pixel[i+2] * D, 1/2.2)
result_pixel[i+3] = D
# for i in range(0,num_pixels,4):
# m = saturate(max(result_pixel[i], result_pixel[i+1], result_pixel[i+2], 1e-6))
# d = max(maxRange / m, 1)
# #d = saturate(math.floor(d) / 255.0)
# d = np.clip((math.floor(d) / 255.0), 0.0, 1.0)
# #TODO TO GAMMA SPACE
# result_pixel[i] = math.pow(result_pixel[i] * d * 255 / maxRange, 1/2.2)
# result_pixel[i+1] = math.pow(result_pixel[i+1] * d * 255 / maxRange, 1/2.2)
# result_pixel[i+2] = math.pow(result_pixel[i+2] * d * 255 / maxRange, 1/2.2)
# result_pixel[i+3] = d
target_image.pixels = result_pixel
@ -457,25 +641,4 @@ def encodeImageRGBDCPU(image, maxRange, outDir, quality):
input_image.filepath_raw = outDir + "/" + input_image.name + ".png"
input_image.file_format = "PNG"
bpy.context.scene.render.image_settings.quality = quality
input_image.save()
# const float rgbdMaxRange = 255.0;
# vec4 toRGBD(vec3 color) {
# float maxRGB = maxEps(max(color.r, max(color.g, color.b)));
# float D = max(rgbdMaxRange / maxRGB, 1.);
# D = clamp(floor(D) / 255.0, 0., 1.);
# vec3 rgb = color.rgb * D;
# // Helps with png quantization.
# rgb = toGammaSpace(rgb);
# return vec4(rgb, D);
# }
# const float Epsilon = 0.0000001;
# #define saturate(x) clamp(x, 0.0, 1.0)
# float maxEps(float x) {
# return max(x, Epsilon);
# }
input_image.save()

View file

@ -62,7 +62,7 @@ class TLM_CV_Filtering:
#SEAM TESTING# #####################
if obj_name in bpy.data.objects:
if obj_name in bpy.context.scene.objects:
override = bpy.data.objects[obj_name].TLM_ObjectProperties.tlm_mesh_filter_override
elif obj_name in scene.TLM_AtlasList:
override = False

View file

@ -0,0 +1,67 @@
import bpy, blf, bgl, os, gpu
from gpu_extras.batch import batch_for_shader
class ViewportDraw:
def __init__(self, context, text):
bakefile = "TLM_Overlay.png"
scriptDir = os.path.dirname(os.path.realpath(__file__))
bakefile_path = os.path.abspath(os.path.join(scriptDir, '..', '..', 'assets/' + bakefile))
image_name = "TLM_Overlay.png"
bpy.ops.image.open(filepath=bakefile_path)
print("Self path: " + bakefile_path)
image = bpy.data.images[image_name]
x = 15
y = 15
w = 400
h = 200
self.shader = gpu.shader.from_builtin('2D_IMAGE')
self.batch = batch_for_shader(
self.shader, 'TRI_FAN',
{
"pos": ((x, y), (x+w, y), (x+w, y+h), (x, y+h)),
"texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)),
},
)
if image.gl_load():
raise Exception()
self.text = text
self.image = image
#self.handle = bpy.types.SpaceView3D.draw_handler_add(self.draw_text_callback, (context,), 'WINDOW', 'POST_PIXEL')
self.handle2 = bpy.types.SpaceView3D.draw_handler_add(self.draw_image_callback, (context,), 'WINDOW', 'POST_PIXEL')
def draw_text_callback(self, context):
font_id = 0
blf.position(font_id, 15, 15, 0)
blf.size(font_id, 20, 72)
blf.draw(font_id, "%s" % (self.text))
def draw_image_callback(self, context):
if self.image:
bgl.glEnable(bgl.GL_BLEND)
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.image.bindcode)
self.shader.bind()
self.shader.uniform_int("image", 0)
self.batch.draw(self.shader)
bgl.glDisable(bgl.GL_BLEND)
def update_text(self, text):
self.text = text
def remove_handle(self):
#bpy.types.SpaceView3D.draw_handler_remove(self.handle, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self.handle2, 'WINDOW')

View file

@ -0,0 +1,259 @@
import bpy
from .. utility import *
def init(self, prev_container):
#TODO - JSON classes
export.scene = """scene.camera.cliphither = 0.1
scene.camera.clipyon = 100
scene.camera.shutteropen = 0
scene.camera.shutterclose = 1
scene.camera.autovolume.enable = 1
scene.camera.lookat.orig = 7.358891 -6.925791 4.958309
scene.camera.lookat.target = 6.707333 -6.31162 4.513038
scene.camera.up = -0.3240135 0.3054208 0.8953956
scene.camera.screenwindow = -1 1 -0.5625 0.5625
scene.camera.lensradius = 0
scene.camera.focaldistance = 10
scene.camera.autofocus.enable = 0
scene.camera.type = "perspective"
scene.camera.oculusrift.barrelpostpro.enable = 0
scene.camera.fieldofview = 39.59776
scene.camera.bokeh.blades = 0
scene.camera.bokeh.power = 3
scene.camera.bokeh.distribution.type = "NONE"
scene.camera.bokeh.scale.x = 0.7071068
scene.camera.bokeh.scale.y = 0.7071068
scene.lights.__WORLD_BACKGROUND_LIGHT__.gain = 2e-05 2e-05 2e-05
scene.lights.__WORLD_BACKGROUND_LIGHT__.transformation = 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1
scene.lights.__WORLD_BACKGROUND_LIGHT__.id = 0
scene.lights.__WORLD_BACKGROUND_LIGHT__.temperature = -1
scene.lights.__WORLD_BACKGROUND_LIGHT__.temperature.normalize = 0
scene.lights.__WORLD_BACKGROUND_LIGHT__.visibility.indirect.diffuse.enable = 1
scene.lights.__WORLD_BACKGROUND_LIGHT__.visibility.indirect.glossy.enable = 1
scene.lights.__WORLD_BACKGROUND_LIGHT__.visibility.indirect.specular.enable = 1
scene.lights.__WORLD_BACKGROUND_LIGHT__.type = "sky2"
scene.lights.__WORLD_BACKGROUND_LIGHT__.dir = 0 0 1
scene.lights.__WORLD_BACKGROUND_LIGHT__.turbidity = 2.2
scene.lights.__WORLD_BACKGROUND_LIGHT__.groundalbedo = 0.5 0.5 0.5
scene.lights.__WORLD_BACKGROUND_LIGHT__.ground.enable = 0
scene.lights.__WORLD_BACKGROUND_LIGHT__.ground.color = 0.5 0.5 0.5
scene.lights.__WORLD_BACKGROUND_LIGHT__.ground.autoscale = 1
scene.lights.__WORLD_BACKGROUND_LIGHT__.distribution.width = 512
scene.lights.__WORLD_BACKGROUND_LIGHT__.distribution.height = 256
scene.lights.__WORLD_BACKGROUND_LIGHT__.visibilitymapcache.enable = 0
scene.lights.2382361116072.gain = 1 1 1
scene.lights.2382361116072.transformation = -0.2908646 0.9551712 -0.05518906 0 -0.7711008 -0.1998834 0.6045247 0 0.5663932 0.2183912 0.7946723 0 4.076245 1.005454 5.903862 1
scene.lights.2382361116072.id = 0
scene.lights.2382361116072.temperature = -1
scene.lights.2382361116072.temperature.normalize = 0
scene.lights.2382361116072.type = "sphere"
scene.lights.2382361116072.color = 1 1 1
scene.lights.2382361116072.power = 0
scene.lights.2382361116072.normalizebycolor = 0
scene.lights.2382361116072.efficency = 0
scene.lights.2382361116072.position = 0 0 0
scene.lights.2382361116072.radius = 0.1
scene.materials.Material2382357175256.type = "disney"
scene.materials.Material2382357175256.basecolor = "0.7 0.7 0.7"
scene.materials.Material2382357175256.subsurface = "0"
scene.materials.Material2382357175256.roughness = "0.2"
scene.materials.Material2382357175256.metallic = "0"
scene.materials.Material2382357175256.specular = "0.5"
scene.materials.Material2382357175256.speculartint = "0"
scene.materials.Material2382357175256.clearcoat = "0"
scene.materials.Material2382357175256.clearcoatgloss = "1"
scene.materials.Material2382357175256.anisotropic = "0"
scene.materials.Material2382357175256.sheen = "0"
scene.materials.Material2382357175256.sheentint = "0"
scene.materials.Material2382357175256.transparency.shadow = 0 0 0
scene.materials.Material2382357175256.id = 3364224
scene.materials.Material2382357175256.emission.gain = 1 1 1
scene.materials.Material2382357175256.emission.power = 0
scene.materials.Material2382357175256.emission.normalizebycolor = 1
scene.materials.Material2382357175256.emission.efficency = 0
scene.materials.Material2382357175256.emission.theta = 90
scene.materials.Material2382357175256.emission.id = 0
scene.materials.Material2382357175256.emission.importance = 1
scene.materials.Material2382357175256.emission.temperature = -1
scene.materials.Material2382357175256.emission.temperature.normalize = 0
scene.materials.Material2382357175256.emission.directlightsampling.type = "AUTO"
scene.materials.Material2382357175256.visibility.indirect.diffuse.enable = 1
scene.materials.Material2382357175256.visibility.indirect.glossy.enable = 1
scene.materials.Material2382357175256.visibility.indirect.specular.enable = 1
scene.materials.Material2382357175256.shadowcatcher.enable = 0
scene.materials.Material2382357175256.shadowcatcher.onlyinfinitelights = 0
scene.materials.Material2382357175256.photongi.enable = 1
scene.materials.Material2382357175256.holdout.enable = 0
scene.materials.Material__0012382357172440.type = "disney"
scene.materials.Material__0012382357172440.basecolor = "0.7 0.7 0.7"
scene.materials.Material__0012382357172440.subsurface = "0"
scene.materials.Material__0012382357172440.roughness = "0.2"
scene.materials.Material__0012382357172440.metallic = "0"
scene.materials.Material__0012382357172440.specular = "0.5"
scene.materials.Material__0012382357172440.speculartint = "0"
scene.materials.Material__0012382357172440.clearcoat = "0"
scene.materials.Material__0012382357172440.clearcoatgloss = "1"
scene.materials.Material__0012382357172440.anisotropic = "0"
scene.materials.Material__0012382357172440.sheen = "0"
scene.materials.Material__0012382357172440.sheentint = "0"
scene.materials.Material__0012382357172440.transparency.shadow = 0 0 0
scene.materials.Material__0012382357172440.id = 6728256
scene.materials.Material__0012382357172440.emission.gain = 1 1 1
scene.materials.Material__0012382357172440.emission.power = 0
scene.materials.Material__0012382357172440.emission.normalizebycolor = 1
scene.materials.Material__0012382357172440.emission.efficency = 0
scene.materials.Material__0012382357172440.emission.theta = 90
scene.materials.Material__0012382357172440.emission.id = 0
scene.materials.Material__0012382357172440.emission.importance = 1
scene.materials.Material__0012382357172440.emission.temperature = -1
scene.materials.Material__0012382357172440.emission.temperature.normalize = 0
scene.materials.Material__0012382357172440.emission.directlightsampling.type = "AUTO"
scene.materials.Material__0012382357172440.visibility.indirect.diffuse.enable = 1
scene.materials.Material__0012382357172440.visibility.indirect.glossy.enable = 1
scene.materials.Material__0012382357172440.visibility.indirect.specular.enable = 1
scene.materials.Material__0012382357172440.shadowcatcher.enable = 0
scene.materials.Material__0012382357172440.shadowcatcher.onlyinfinitelights = 0
scene.materials.Material__0012382357172440.photongi.enable = 1
scene.materials.Material__0012382357172440.holdout.enable = 0
scene.objects.23823611086320.material = "Material2382357175256"
scene.objects.23823611086320.ply = "mesh-00000.ply"
scene.objects.23823611086320.camerainvisible = 0
scene.objects.23823611086320.id = 1326487202
scene.objects.23823611086320.appliedtransformation = 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1
scene.objects.23823611279760.material = "Material__0012382357172440"
scene.objects.23823611279760.ply = "mesh-00001.ply"
scene.objects.23823611279760.camerainvisible = 0
scene.objects.23823611279760.id = 3772660237
scene.objects.23823611279760.appliedtransformation = 5 0 0 0 0 5 0 0 0 0 5 0 0 0 0 1
"""
export.config = """context.verbose = 1
accelerator.type = "AUTO"
accelerator.instances.enable = 1
accelerator.motionblur.enable = 1
accelerator.bvh.builder.type = "EMBREE_BINNED_SAH"
accelerator.bvh.treetype = 4
accelerator.bvh.costsamples = 0
accelerator.bvh.isectcost = 80
accelerator.bvh.travcost = 10
accelerator.bvh.emptybonus = 0.5
scene.epsilon.min = "1e-05"
scene.epsilon.max = "0.1"
scene.file = "scene.scn"
images.scale = 1
lightstrategy.type = "LOG_POWER"
native.threads.count = 8
renderengine.type = "BAKECPU"
path.pathdepth.total = "7"
path.pathdepth.diffuse = "5"
path.pathdepth.glossy = "5"
path.pathdepth.specular = "6"
path.hybridbackforward.enable = "0"
path.hybridbackforward.partition = "0.8"
path.hybridbackforward.glossinessthreshold = "0.049"
path.russianroulette.depth = 3
path.russianroulette.cap = 0.5
path.clamping.variance.maxvalue = 0
path.forceblackbackground.enable = "0"
sampler.type = "SOBOL"
sampler.imagesamples.enable = 1
sampler.sobol.adaptive.strength = "0.9"
sampler.sobol.adaptive.userimportanceweight = 0.75
sampler.sobol.bucketsize = "16"
sampler.sobol.tilesize = "16"
sampler.sobol.supersampling = "1"
sampler.sobol.overlapping = "1"
path.photongi.sampler.type = "METROPOLIS"
path.photongi.photon.maxcount = 100000000
path.photongi.photon.maxdepth = 4
path.photongi.photon.time.start = 0
path.photongi.photon.time.end = -1
path.photongi.visibility.lookup.radius = 0
path.photongi.visibility.lookup.normalangle = 10
path.photongi.visibility.targethitrate = 0.99
path.photongi.visibility.maxsamplecount = 1048576
path.photongi.glossinessusagethreshold = 0.05
path.photongi.indirect.enabled = 0
path.photongi.indirect.maxsize = 0
path.photongi.indirect.haltthreshold = 0.05
path.photongi.indirect.lookup.radius = 0
path.photongi.indirect.lookup.normalangle = 10
path.photongi.indirect.usagethresholdscale = 8
path.photongi.indirect.filter.radiusscale = 3
path.photongi.caustic.enabled = 0
path.photongi.caustic.maxsize = 100000
path.photongi.caustic.updatespp = 8
path.photongi.caustic.updatespp.radiusreduction = 0.96
path.photongi.caustic.updatespp.minradius = 0.003
path.photongi.caustic.lookup.radius = 0.15
path.photongi.caustic.lookup.normalangle = 10
path.photongi.debug.type = "none"
path.photongi.persistent.file = ""
path.photongi.persistent.safesave = 1
film.filter.type = "BLACKMANHARRIS"
film.filter.width = 2
opencl.platform.index = -1
film.width = 960
film.height = 600
film.safesave = 1
film.noiseestimation.step = "32"
film.noiseestimation.warmup = "8"
film.noiseestimation.filter.scale = 4
batch.haltnoisethreshold = 0.01
batch.haltnoisethreshold.step = 64
batch.haltnoisethreshold.warmup = 64
batch.haltnoisethreshold.filter.enable = 1
batch.haltnoisethreshold.stoprendering.enable = 1
batch.halttime = "0"
batch.haltspp = 32
film.outputs.safesave = 1
film.outputs.0.type = "RGB_IMAGEPIPELINE"
film.outputs.0.filename = "RGB_IMAGEPIPELINE_0.png"
film.outputs.0.index = "0"
film.imagepipelines.000.0.type = "NOP"
film.imagepipelines.000.1.type = "TONEMAP_LINEAR"
film.imagepipelines.000.1.scale = "1"
film.imagepipelines.000.2.type = "GAMMA_CORRECTION"
film.imagepipelines.000.2.value = "2.2"
film.imagepipelines.000.radiancescales.0.enabled = "1"
film.imagepipelines.000.radiancescales.0.globalscale = "1"
film.imagepipelines.000.radiancescales.0.rgbscale = "1" "1" "1"
periodicsave.film.outputs.period = 0
periodicsave.film.period = 0
periodicsave.film.filename = "film.flm"
periodicsave.resumerendering.period = 0
periodicsave.resumerendering.filename = "rendering.rsm"
resumerendering.filesafe = 1
debug.renderconfig.parse.print = 0
debug.scene.parse.print = 0
screen.refresh.interval = 100
screen.tool.type = "CAMERA_EDIT"
screen.tiles.pending.show = 1
screen.tiles.converged.show = 0
screen.tiles.notconverged.show = 0
screen.tiles.passcount.show = 0
screen.tiles.error.show = 0
bake.minmapautosize = 64
bake.maxmapautosize = 1024
bake.powerof2autosize.enable = 1
bake.skipexistingmapfiles = 1
film.imagepipelines.1.0.type = "NOP"
bake.maps.0.type = "COMBINED"
bake.maps.0.filename = "23823611086320.exr"
bake.maps.0.imagepipelineindex = 1
bake.maps.0.width = 512
bake.maps.0.height = 512
bake.maps.0.autosize.enabled = 1
bake.maps.0.uvindex = 0
bake.maps.0.objectnames = "23823611086320"
bake.maps.1.type = "COMBINED"
bake.maps.1.filename = "23823611279760.exr"
bake.maps.1.imagepipelineindex = 1
bake.maps.1.width = 512
bake.maps.1.height = 512
bake.maps.1.autosize.enabled = 1
bake.maps.1.uvindex = 0
bake.maps.1.objectnames = "23823611279760"
"""

View file

@ -0,0 +1,243 @@
import bpy, math
#from . import cache
from .. utility import *
def init(self, prev_container):
#store_existing(prev_container)
#set_settings()
configure_world()
configure_lights()
configure_meshes(self)
def configure_world():
pass
def configure_lights():
pass
def configure_meshes(self):
for mat in bpy.data.materials:
if mat.users < 1:
bpy.data.materials.remove(mat)
for mat in bpy.data.materials:
if mat.name.startswith("."):
if "_Original" in mat.name:
bpy.data.materials.remove(mat)
for image in bpy.data.images:
if image.name.endswith("_baked"):
bpy.data.images.remove(image, do_unlink=True)
iterNum = 1
currentIterNum = 0
scene = bpy.context.scene
for obj in scene.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
obj.hide_select = False #Remember to toggle this back
currentIterNum = currentIterNum + 1
obj.octane.baking_group_id = 1 + currentIterNum #0 doesn't exist, 1 is neutral and 2 is first baked object
print("Obj: " + obj.name + " set to baking group: " + str(obj.octane.baking_group_id))
for slot in obj.material_slots:
if "." + slot.name + '_Original' in bpy.data.materials:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("The material: " + slot.name + " shifted to " + "." + slot.name + '_Original')
slot.material = bpy.data.materials["." + slot.name + '_Original']
objWasHidden = False
#For some reason, a Blender bug might prevent invisible objects from being smart projected
#We will turn the object temporarily visible
obj.hide_viewport = False
obj.hide_set(False)
#Configure selection
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
obs = bpy.context.view_layer.objects
active = obs.active
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 obj: " + obj.name)
uvmap = uv_layers.new(name=uv_channel)
uv_layers.active_index = len(uv_layers) - 1
print("Setting active UV to: " + uv_layers.active_index)
#If lightmap
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "Lightmap":
bpy.ops.uv.lightmap_pack('EXEC_SCREEN', PREF_CONTEXT='ALL_FACES', PREF_MARGIN_DIV=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin)
#If smart project
elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "SmartProject":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Smart Project B")
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
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 obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "Xatlas":
Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj)
elif obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("ATLAS GROUP: " + obj.TLM_ObjectProperties.tlm_atlas_pointer)
else: #if copy existing
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Copied Existing UV Map for object: " + obj.name)
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Existing UV map found for obj: " + obj.name)
for i in range(0, len(uv_layers)):
if uv_layers[i].name == uv_channel:
uv_layers.active_index = i
break
set_camera()
def set_camera():
cam_name = "TLM-BakeCam"
if not cam_name in bpy.context.scene:
camera = bpy.data.cameras.new(cam_name)
camobj_name = "TLM-BakeCam-obj"
cam_obj = bpy.data.objects.new(camobj_name, camera)
bpy.context.collection.objects.link(cam_obj)
cam_obj.location = ((0,0,0))
bpy.context.scene.camera = cam_obj
def set_settings():
scene = bpy.context.scene
cycles = scene.cycles
scene.render.engine = "CYCLES"
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
if engineProperties.tlm_quality == "0":
cycles.samples = 32
cycles.max_bounces = 1
cycles.diffuse_bounces = 1
cycles.glossy_bounces = 1
cycles.transparent_max_bounces = 1
cycles.transmission_bounces = 1
cycles.volume_bounces = 1
cycles.caustics_reflective = False
cycles.caustics_refractive = False
elif engineProperties.tlm_quality == "1":
cycles.samples = 64
cycles.max_bounces = 2
cycles.diffuse_bounces = 2
cycles.glossy_bounces = 2
cycles.transparent_max_bounces = 2
cycles.transmission_bounces = 2
cycles.volume_bounces = 2
cycles.caustics_reflective = False
cycles.caustics_refractive = False
elif engineProperties.tlm_quality == "2":
cycles.samples = 512
cycles.max_bounces = 2
cycles.diffuse_bounces = 2
cycles.glossy_bounces = 2
cycles.transparent_max_bounces = 2
cycles.transmission_bounces = 2
cycles.volume_bounces = 2
cycles.caustics_reflective = False
cycles.caustics_refractive = False
elif engineProperties.tlm_quality == "3":
cycles.samples = 1024
cycles.max_bounces = 256
cycles.diffuse_bounces = 256
cycles.glossy_bounces = 256
cycles.transparent_max_bounces = 256
cycles.transmission_bounces = 256
cycles.volume_bounces = 256
cycles.caustics_reflective = False
cycles.caustics_refractive = False
elif engineProperties.tlm_quality == "4":
cycles.samples = 2048
cycles.max_bounces = 512
cycles.diffuse_bounces = 512
cycles.glossy_bounces = 512
cycles.transparent_max_bounces = 512
cycles.transmission_bounces = 512
cycles.volume_bounces = 512
cycles.caustics_reflective = True
cycles.caustics_refractive = True
else: #Custom
pass
def store_existing(prev_container):
scene = bpy.context.scene
cycles = scene.cycles
selected = []
for obj in bpy.context.scene.objects:
if obj.select_get():
selected.append(obj.name)
prev_container["settings"] = [
cycles.samples,
cycles.max_bounces,
cycles.diffuse_bounces,
cycles.glossy_bounces,
cycles.transparent_max_bounces,
cycles.transmission_bounces,
cycles.volume_bounces,
cycles.caustics_reflective,
cycles.caustics_refractive,
cycles.device,
scene.render.engine,
bpy.context.view_layer.objects.active,
selected,
[scene.render.resolution_x, scene.render.resolution_y]
]

View file

@ -0,0 +1,71 @@
import bpy, os
def bake():
cam_name = "TLM-BakeCam-obj"
if cam_name in bpy.context.scene.objects:
print("Camera found...")
camera = bpy.context.scene.objects[cam_name]
camera.data.octane.baking_camera = True
for obj in bpy.context.scene.objects:
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(False)
iterNum = 2
currentIterNum = 1
for obj in bpy.context.scene.objects:
if obj.type == "MESH":
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
iterNum = iterNum + 1
if iterNum > 1:
iterNum = iterNum - 1
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:
currentIterNum = currentIterNum + 1
scene = bpy.context.scene
print("Baking obj: " + obj.name)
print("Baking ID: " + str(currentIterNum) + " out of " + str(iterNum))
bpy.ops.object.select_all(action='DESELECT')
camera.data.octane.baking_group_id = currentIterNum
savedir = os.path.dirname(bpy.data.filepath)
user_dir = scene.TLM_Engine3Properties.tlm_lightmap_savedir
directory = os.path.join(savedir, user_dir)
image_settings = bpy.context.scene.render.image_settings
image_settings.file_format = "HDR"
image_settings.color_depth = '32'
filename = os.path.join(directory, "LM") + "_" + obj.name + ".hdr"
bpy.context.scene.render.filepath = filename
resolution = int(obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution)
bpy.context.scene.render.resolution_x = resolution
bpy.context.scene.render.resolution_y = resolution
bpy.ops.render.render(write_still=True)
else:
print("No baking camera found")
print("Baking in Octane!")

View file

@ -106,7 +106,7 @@ def postpack():
rect = []
#For each object that targets the atlas
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_postpack_object:
if obj.TLM_ObjectProperties.tlm_postatlas_pointer == atlas.name:
@ -156,7 +156,13 @@ def postpack():
obj = bpy.data.objects[aob]
for idx, layer in enumerate(obj.data.uv_layers):
if layer.name == "UVMap_Lightmap":
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel
else:
uv_channel = "UVMap_Lightmap"
if layer.name == uv_channel:
obj.data.uv_layers.active_index = idx
print("UVLayer set to: " + str(obj.data.uv_layers.active_index))
@ -194,7 +200,7 @@ def postpack():
print("Written: " + str(os.path.join(lightmap_directory, atlas.name + end + formatEnc)))
#Change the material for each material, slot
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_postpack_object:
if obj.TLM_ObjectProperties.tlm_postatlas_pointer == atlas.name:
@ -219,7 +225,7 @@ def postpack():
existing_image.user_clear()
#Add dilation map here...
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_postpack_object:
if obj.TLM_ObjectProperties.tlm_postatlas_pointer == atlas.name:

View file

@ -1,5 +1,5 @@
import bpy.ops as O
import bpy, os, re, sys, importlib, struct, platform, subprocess, threading, string, bmesh
import bpy, os, re, sys, importlib, struct, platform, subprocess, threading, string, bmesh, shutil, glob, uuid
from io import StringIO
from threading import Thread
from queue import Queue, Empty
@ -81,15 +81,8 @@ def save_image(image):
image.filepath_raw = savepath
# if "Normal" in image.name:
# bpy.context.scene.render.image_settings.quality = 90
# image.save_render( filepath = image.filepath_raw, scene = bpy.context.scene )
# else:
image.save()
def get_file_size(filepath):
size = "Unpack Files"
try:
@ -141,7 +134,7 @@ def check_is_org_material(self,material):
def clean_empty_materials(self):
for obj in bpy.data.objects:
for obj in bpy.context.scene.objects:
for slot in obj.material_slots:
mat = slot.material
if mat is None:
@ -319,6 +312,11 @@ def lightmap_to_ao(material,lightmap_node):
# https://github.com/mattedicksoncom/blender-xatlas/
###########################################################
def gen_safe_name():
genId = uuid.uuid4().hex
# genId = "u_" + genId.replace("-","_")
return "u_" + genId
def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
blender_xatlas = importlib.util.find_spec("blender_xatlas")
@ -330,32 +328,54 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
packOptions = bpy.context.scene.pack_tool
chartOptions = bpy.context.scene.chart_tool
sharedProperties = bpy.context.scene.shared_properties
#sharedProperties.unwrapSelection
context = bpy.context
if obj.type == 'MESH':
context.view_layer.objects.active = obj
if obj.data.users > 1:
obj.data = obj.data.copy() #make single user copy
uv_layers = obj.data.uv_layers
#setup the lightmap uvs
uvName = "UVMap_Lightmap"
if sharedProperties.lightmapUVChoiceType == "NAME":
uvName = sharedProperties.lightmapUVName
elif sharedProperties.lightmapUVChoiceType == "INDEX":
if sharedProperties.lightmapUVIndex < len(uv_layers):
uvName = uv_layers[sharedProperties.lightmapUVIndex].name
#save whatever mode the user was in
startingMode = bpy.context.object.mode
selected_objects = bpy.context.selected_objects
if not uvName in uv_layers:
uvmap = uv_layers.new(name=uvName)
uv_layers.active_index = len(uv_layers) - 1
else:
for i in range(0, len(uv_layers)):
if uv_layers[i].name == uvName:
uv_layers.active_index = i
obj.select_set(True)
#check something is actually selected
#external function/operator will select them
if len(selected_objects) == 0:
print("Nothing Selected")
self.report({"WARNING"}, "Nothing Selected, please select Something")
return {'FINISHED'}
#store the names of objects to be lightmapped
rename_dict = dict()
safe_dict = dict()
#make sure all the objects have ligthmap uvs
for obj in selected_objects:
if obj.type == 'MESH':
safe_name = gen_safe_name();
rename_dict[obj.name] = (obj.name,safe_name)
safe_dict[safe_name] = obj.name
context.view_layer.objects.active = obj
if obj.data.users > 1:
obj.data = obj.data.copy() #make single user copy
uv_layers = obj.data.uv_layers
#setup the lightmap uvs
uvName = "UVMap_Lightmap"
if sharedProperties.lightmapUVChoiceType == "NAME":
uvName = sharedProperties.lightmapUVName
elif sharedProperties.lightmapUVChoiceType == "INDEX":
if sharedProperties.lightmapUVIndex < len(uv_layers):
uvName = uv_layers[sharedProperties.lightmapUVIndex].name
if not uvName in uv_layers:
uvmap = uv_layers.new(name=uvName)
uv_layers.active_index = len(uv_layers) - 1
else:
for i in range(0, len(uv_layers)):
if uv_layers[i].name == uvName:
uv_layers.active_index = i
obj.select_set(True)
#save all the current edges
if sharedProperties.packOnly:
@ -381,8 +401,11 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
bpy.ops.object.mode_set(mode='OBJECT')
#Create a fake obj export to a string
#Will strip this down further later
fakeFile = StringIO()
blender_xatlas.export_obj_simple.save(
rename_dict=rename_dict,
context=bpy.context,
filepath=fakeFile,
mainUVChoiceType=sharedProperties.mainUVChoiceType,
@ -393,20 +416,26 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
use_mesh_modifiers=True,
use_edges=True,
use_smooth_groups=False,
use_smooth_groups_bitflags=False,
use_smooth_groups_bitflags=False,
use_normals=True,
use_uvs=True,
use_materials=False,
use_triangles=False,
use_nurbs=False,
use_vertex_groups=False,
use_nurbs=False,
use_vertex_groups=False,
use_blen_objects=True,
group_by_object=False,
group_by_material=False,
keep_vertex_order=False,
)
file_path = os.path.dirname(os.path.abspath(blender_xatlas.__file__))
#print just for reference
# print(fakeFile.getvalue())
#get the path to xatlas
#file_path = os.path.dirname(os.path.abspath(__file__))
scriptsDir = bpy.utils.user_resource('SCRIPTS', "addons")
file_path = os.path.join(scriptsDir, "blender_xatlas")
if platform.system() == "Windows":
xatlas_path = os.path.join(file_path, "xatlas", "xatlas-blender.exe")
elif platform.system() == "Linux":
@ -458,6 +487,8 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
shell=True
)
print(xatlas_path)
#shove the fake file in stdin
stdin = xatlas_process.stdin
value = bytes(fakeFile.getvalue() + "\n", 'UTF-8') #The \n is needed to end the input properly
@ -482,17 +513,17 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
obName: string = ""
uvArray: List[float] = field(default_factory=list)
faceArray: List[int] = field(default_factory=list)
convertedObjects = []
uvArrayComplete = []
#search through the out put for STARTOBJ
#then start reading the objects
obTest = None
startRead = False
for line in outObj.splitlines():
line_split = line.split()
if not line_split:
@ -504,14 +535,14 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
print("Start reading the objects----------------------------------------")
startRead = True
# obTest = uvObject()
if startRead:
#if it's a new obj
if line_start == 'o':
#if there is already an object append it
if obTest is not None:
convertedObjects.append(obTest)
obTest = uvObject() #create new uv object
obTest.obName = line_split[1]
@ -536,9 +567,9 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
#append the final object
convertedObjects.append(obTest)
# print(convertedObjects)
print(convertedObjects)
#apply the output-------------------------------------------------------------
#copy the uvs to the original objects
# objIndex = 0
@ -548,7 +579,7 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
bpy.ops.object.select_all(action='DESELECT')
obTest = importObject
obTest.obName = safe_dict[obTest.obName] #probably shouldn't just replace it
bpy.context.scene.objects[obTest.obName].select_set(True)
context.view_layer.objects.active = bpy.context.scene.objects[obTest.obName]
bpy.ops.object.mode_set(mode = 'OBJECT')
@ -563,7 +594,7 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
nFaces = len(bm.faces)
#need to ensure lookup table for some reason?
if hasattr(bm.faces, "ensure_lookup_table"):
if hasattr(bm.faces, "ensure_lookup_table"):
bm.faces.ensure_lookup_table()
#loop through the faces
@ -601,7 +632,7 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
currentObject = bpy.context.scene.objects[edgeList['object']]
bm = bmesh.new()
bm.from_mesh(currentObject.data)
if hasattr(bm.edges, "ensure_lookup_table"):
if hasattr(bm.edges, "ensure_lookup_table"):
bm.edges.ensure_lookup_table()
#assume that all the triangulated edges come after the original edges
@ -617,6 +648,27 @@ def Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj):
bm.free()
bpy.ops.object.mode_set(mode='EDIT')
#End setting the quads back again------------------------------------------------------------
#End setting the quads back again-------------------------------------------------------------
print("Finished Xatlas----------------------------------------")
#select the original objects that were selected
for objectName in rename_dict:
if objectName[0] in bpy.context.scene.objects:
current_object = bpy.context.scene.objects[objectName[0]]
current_object.select_set(True)
context.view_layer.objects.active = current_object
bpy.ops.object.mode_set(mode=startingMode)
print("Finished Xatlas----------------------------------------")
return {'FINISHED'}
def transfer_assets(copy, source, destination):
for filename in glob.glob(os.path.join(source, '*.*')):
shutil.copy(filename, destination)
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)

View file

@ -3,7 +3,7 @@ import arm.assets
import bpy
from bpy.types import Menu, Panel, UIList
from bpy.props import *
from arm.lightmapper import operators, properties, utility, keymap
from arm.lightmapper import operators, properties, utility
class ArmBakeListItem(bpy.types.PropertyGroup):
obj: PointerProperty(type=bpy.types.Object, description="The object to bake")
@ -361,7 +361,6 @@ def register():
operators.register()
properties.register()
keymap.register()
def unregister():
bpy.utils.unregister_class(ArmBakeListItem)
@ -380,5 +379,4 @@ def unregister():
#Unregister lightmapper
operators.unregister()
properties.unregister()
keymap.unregister()
properties.unregister()

View file

@ -20,6 +20,7 @@ import arm.utils
from arm.lightmapper.utility import icon
from arm.lightmapper.properties.denoiser import oidn, optix
from arm.lightmapper.panels import scene
import importlib
@ -73,9 +74,18 @@ class ARM_PT_ObjectPropsPanel(bpy.types.Panel):
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_resolution")
row.prop(obj.TLM_ObjectProperties, "tlm_use_default_channel")
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
row = layout.row()
row.prop_search(obj.TLM_ObjectProperties, "tlm_uv_channel", obj.data, "uv_layers", text='UV Channel')
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_unwrap_mode")
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_resolution")
if obj.TLM_ObjectProperties.tlm_use_default_channel:
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_unwrap_mode")
row = layout.row()
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
@ -93,7 +103,6 @@ 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()
@ -1482,423 +1491,6 @@ class ARM_PT_BakePanel(bpy.types.Panel):
layout.prop(item, "res_x")
layout.prop(item, "res_y")
else:
scene = context.scene
sceneProperties = scene.TLM_SceneProperties
row = layout.row(align=True)
row = layout.row(align=True)
#We list LuxCoreRender as available, by default we assume Cycles exists
row.prop(sceneProperties, "tlm_lightmap_engine")
if sceneProperties.tlm_lightmap_engine == "Cycles":
#CYCLES SETTINGS HERE
engineProperties = scene.TLM_EngineProperties
row = layout.row(align=True)
row.label(text="General Settings")
row = layout.row(align=True)
row.operator("tlm.build_lightmaps")
row = layout.row(align=True)
row.operator("tlm.clean_lightmaps")
row = layout.row(align=True)
row.operator("tlm.explore_lightmaps")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_apply_on_unwrap")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_headless")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_alert_on_finish")
if sceneProperties.tlm_alert_on_finish:
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_alert_sound")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_verbose")
#row = layout.row(align=True)
#row.prop(sceneProperties, "tlm_compile_statistics")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_override_bg_color")
if sceneProperties.tlm_override_bg_color:
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_override_color")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_reset_uv")
row = layout.row(align=True)
try:
if bpy.context.scene["TLM_Buildstat"] is not None:
row.label(text="Last build completed in: " + str(bpy.context.scene["TLM_Buildstat"][0]))
except:
pass
row = layout.row(align=True)
row.label(text="Cycles Settings")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_quality")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_resolution_scale")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_bake_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_lighting_mode")
if scene.TLM_EngineProperties.tlm_bake_mode == "Background":
row = layout.row(align=True)
row.label(text="Warning! Background mode is currently unstable", icon_value=2)
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_network_render")
if sceneProperties.tlm_network_render:
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_network_paths")
#row = layout.row(align=True)
#row.prop(sceneProperties, "tlm_network_dir")
row = layout.row(align=True)
row = layout.row(align=True)
row.prop(engineProperties, "tlm_caching_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_directional_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_lightmap_savedir")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_dilation_margin")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_exposure_multiplier")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_setting_supersample")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_metallic_clamp")
elif sceneProperties.tlm_lightmap_engine == "LuxCoreRender":
#LUXCORE SETTINGS HERE
luxcore_available = False
#Look for Luxcorerender in the renderengine classes
for engine in bpy.types.RenderEngine.__subclasses__():
if engine.bl_idname == "LUXCORE":
luxcore_available = True
break
row = layout.row(align=True)
if not luxcore_available:
row.label(text="Please install BlendLuxCore.")
else:
row.label(text="LuxCoreRender not yet available.")
elif sceneProperties.tlm_lightmap_engine == "OctaneRender":
#LUXCORE SETTINGS HERE
octane_available = False
row = layout.row(align=True)
row.label(text="Octane Render not yet available.")
##################
#DENOISE SETTINGS!
row = layout.row(align=True)
row.label(text="Denoise Settings")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_denoise_use")
row = layout.row(align=True)
if sceneProperties.tlm_denoise_use:
row.prop(sceneProperties, "tlm_denoise_engine", expand=True)
row = layout.row(align=True)
if sceneProperties.tlm_denoise_engine == "Integrated":
row.label(text="No options for Integrated.")
elif sceneProperties.tlm_denoise_engine == "OIDN":
denoiseProperties = scene.TLM_OIDNEngineProperties
row.prop(denoiseProperties, "tlm_oidn_path")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_verbose")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_threads")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_maxmem")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_affinity")
# row = layout.row(align=True)
# row.prop(denoiseProperties, "tlm_denoise_ao")
elif sceneProperties.tlm_denoise_engine == "Optix":
denoiseProperties = scene.TLM_OptixEngineProperties
row.prop(denoiseProperties, "tlm_optix_path")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_optix_verbose")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_optix_maxmem")
##################
#FILTERING SETTINGS!
row = layout.row(align=True)
row.label(text="Filtering Settings")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_filtering_use")
row = layout.row(align=True)
if sceneProperties.tlm_filtering_use:
if sceneProperties.tlm_filtering_engine == "OpenCV":
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
row = layout.row(align=True)
row.label(text="OpenCV is not installed. Install it below.")
row = layout.row(align=True)
row.label(text="It is recommended to install as administrator.")
row = layout.row(align=True)
row.operator("tlm.install_opencv_lightmaps")
else:
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_mode")
row = layout.row(align=True)
if scene.TLM_SceneProperties.tlm_filtering_mode == "Gaussian":
row.prop(scene.TLM_SceneProperties, "tlm_filtering_gaussian_strength")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Box":
row.prop(scene.TLM_SceneProperties, "tlm_filtering_box_strength")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Bilateral":
row.prop(scene.TLM_SceneProperties, "tlm_filtering_bilateral_diameter")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_bilateral_color_deviation")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_bilateral_coordinate_deviation")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
else:
row.prop(scene.TLM_SceneProperties, "tlm_filtering_median_kernel", expand=True)
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
else:
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_numpy_filtering_mode")
##################
#ENCODING SETTINGS!
row = layout.row(align=True)
row.label(text="Encoding Settings")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_encoding_use")
row = layout.row(align=True)
if sceneProperties.tlm_encoding_use:
if scene.TLM_EngineProperties.tlm_bake_mode == "Background":
row.label(text="Encoding options disabled in background mode")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_encoding_device", expand=True)
row = layout.row(align=True)
if sceneProperties.tlm_encoding_device == "CPU":
row.prop(sceneProperties, "tlm_encoding_mode_a", expand=True)
else:
row.prop(sceneProperties, "tlm_encoding_mode_b", expand=True)
if sceneProperties.tlm_encoding_device == "CPU":
if sceneProperties.tlm_encoding_mode_a == "RGBM":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_encoding_range")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_decoder_setup")
if sceneProperties.tlm_encoding_mode_a == "RGBD":
pass
if sceneProperties.tlm_encoding_mode_a == "HDR":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_format")
else:
if sceneProperties.tlm_encoding_mode_b == "RGBM":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_encoding_range")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_decoder_setup")
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_encoding_mode_b == "HDR":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_format")
##################
#SELECTION OPERATORS!
row = layout.row(align=True)
row.label(text="Selection Operators")
row = layout.row(align=True)
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]
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()
if sceneProperties.tlm_mesh_lightmap_unwrap_mode != "AtlasGroupA":
row.prop(sceneProperties, "tlm_mesh_lightmap_resolution")
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_unwrap_margin")
row = layout.row(align=True)
row.operator("tlm.remove_uv_selection")
row = layout.row(align=True)
row.operator("tlm.select_lightmapped_objects")
row = layout.row(align=True)
##################
#Additional settings
row = layout.row(align=True)
row.label(text="Additional options")
sceneProperties = scene.TLM_SceneProperties
atlasListItem = scene.TLM_AtlasListItem
atlasList = scene.TLM_AtlasList
postatlasListItem = scene.TLM_PostAtlasListItem
postatlasList = scene.TLM_PostAtlasList
layout.label(text="Atlas Groups")
row = layout.row()
row.prop(sceneProperties, "tlm_atlas_mode", expand=True)
if sceneProperties.tlm_atlas_mode == "Prepack":
rows = 2
if len(atlasList) > 1:
rows = 4
row = layout.row()
row.template_list("TLM_UL_AtlasList", "Atlas List", scene, "TLM_AtlasList", scene, "TLM_AtlasListItem", 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("ARM_MT_BakeListSpecials", icon='DOWNARROW_HLT', text="")
# if len(scene.TLM_AtlasList) > 1:
# col.separator()
# op = col.operator("arm_bakelist.move_item", icon='TRIA_UP', text="")
# op.direction = 'UP'
# op = col.operator("arm_bakelist.move_item", icon='TRIA_DOWN', text="")
# op.direction = 'DOWN'
if atlasListItem >= 0 and len(atlasList) > 0:
item = atlasList[atlasListItem]
#layout.prop_search(item, "obj", bpy.data, "objects", text="Object")
#layout.prop(item, "res_x")
layout.prop(item, "tlm_atlas_lightmap_unwrap_mode")
layout.prop(item, "tlm_atlas_lightmap_resolution")
layout.prop(item, "tlm_atlas_unwrap_margin")
amount = 0
for obj in bpy.data.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
layout.label(text="Objects: " + str(amount))
# layout.use_property_split = True
# layout.use_property_decorate = False
# layout.label(text="Enable for selection")
# layout.label(text="Disable for selection")
# layout.label(text="Something...")
else:
layout.label(text="Postpacking is unstable.")
rows = 2
if len(atlasList) > 1:
rows = 4
row = layout.row()
row.template_list("TLM_UL_PostAtlasList", "PostList", scene, "TLM_PostAtlasList", scene, "TLM_PostAtlasListItem", rows=rows)
col = row.column(align=True)
col.operator("tlm_postatlaslist.new_item", icon='ADD', text="")
col.operator("tlm_postatlaslist.delete_item", icon='REMOVE', text="")
if postatlasListItem >= 0 and len(postatlasList) > 0:
item = postatlasList[postatlasListItem]
layout.prop(item, "tlm_atlas_lightmap_resolution")
#Below list object counter
amount = 0
utilized = 0
atlasUsedArea = 0
atlasSize = item.tlm_atlas_lightmap_resolution
for obj in bpy.data.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_postpack_object:
if obj.TLM_ObjectProperties.tlm_postatlas_pointer == item.name:
amount = amount + 1
atlasUsedArea += int(obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution) ** 2
row = layout.row()
row.prop(item, "tlm_atlas_repack_on_cleanup")
#TODO SET A CHECK FOR THIS! ADD A CV2 CHECK TO UTILITY!
cv2 = True
if cv2:
row = layout.row()
row.prop(item, "tlm_atlas_dilation")
layout.label(text="Objects: " + str(amount))
utilized = atlasUsedArea / (int(atlasSize) ** 2)
layout.label(text="Utilized: " + str(utilized * 100) + "%")
if (utilized * 100) > 100:
layout.label(text="Warning! Overflow not yet supported")
class ArmGenLodButton(bpy.types.Operator):
"""Automatically generate LoD levels."""
bl_idname = 'arm.generate_lod'
@ -2671,6 +2263,13 @@ def register():
bpy.utils.register_class(ArmoryUpdateListAndroidEmulatorRunButton)
bpy.utils.register_class(ArmoryUpdateListInstalledVSButton)
bpy.utils.register_class(scene.TLM_PT_Settings)
bpy.utils.register_class(scene.TLM_PT_Denoise)
bpy.utils.register_class(scene.TLM_PT_Filtering)
bpy.utils.register_class(scene.TLM_PT_Encoding)
bpy.utils.register_class(scene.TLM_PT_Utility)
bpy.utils.register_class(scene.TLM_PT_Additional)
bpy.types.VIEW3D_HT_header.append(draw_view3d_header)
bpy.types.VIEW3D_MT_object.append(draw_view3d_object_menu)
bpy.types.NODE_MT_context_menu.append(draw_custom_node_menu)
@ -2743,3 +2342,10 @@ def unregister():
bpy.utils.unregister_class(ArmSyncProxyButton)
bpy.utils.unregister_class(ArmPrintTraitsButton)
bpy.utils.unregister_class(ARM_PT_MaterialNodePanel)
bpy.utils.unregister_class(scene.TLM_PT_Settings)
bpy.utils.unregister_class(scene.TLM_PT_Denoise)
bpy.utils.unregister_class(scene.TLM_PT_Filtering)
bpy.utils.unregister_class(scene.TLM_PT_Encoding)
bpy.utils.unregister_class(scene.TLM_PT_Utility)
bpy.utils.unregister_class(scene.TLM_PT_Additional)