Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

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

View File

@ -0,0 +1,22 @@
import bpy
tlm_keymaps = []
def register():
if not bpy.app.background:
winman = bpy.context.window_manager
keyman = winman.keyconfigs.addon.keymaps.new(name='Window', space_type='EMPTY', region_type="WINDOW")
#TODO - In Leenkx3D, 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)
def unregister():
winman = bpy.context.window_manager
for keyman in tlm_keymaps:
winman.keyconfigs.addon.keymaps.remove(keyman)
del tlm_keymaps[:]

View File

@ -0,0 +1,27 @@
import socket, json, os
def connect_client(machine, port, blendpath, obj_num):
# Create a socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to the remote host and port
sock.connect((machine, port))
#0: Blendpath,
#1: For all designated objects, run from 0 to number; 0 indicates all
args = [blendpath, obj_num]
command = json.dumps({'call':1, 'command':1, 'args':args})
# Send a request to the host
sock.send((command).encode())
# Get the host's response, no more than, say, 1,024 bytes
response_data = sock.recv(1024)
print(response_data.decode())
# Terminate
sock.close()

View File

@ -0,0 +1,71 @@
#!/usr/bin/env python3
import bpy, socket, json, subprocess, os, platform, subprocess, select
def startServer():
active = True
baking = False
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 9898))
sock.listen(1)
print("Server started")
while active:
connection,address = sock.accept()
data = connection.recv(1024)
if data:
parsed_data = json.loads(data.decode())
if parsed_data["call"] == 0: #Ping
print("Pinged by: " + str(connection.getsockname()))
connection.sendall(("Ping callback").encode())
elif parsed_data["call"] == 1: #Command
if parsed_data["command"] == 0: #Shutdown
print("Server shutdown")
active = False
if parsed_data["command"] == 1: #Baking
print("Baking...")
args = parsed_data["args"]
blenderpath = bpy.app.binary_path
if not baking:
baking = True
pipe = subprocess.Popen([blenderpath, "-b", str(args[0]), "--python-expr", 'import bpy; import thelightmapper; thelightmapper.addon.utility.build.prepare_build(0, True);'], shell=True, stdout=subprocess.PIPE)
stdout = pipe.communicate()[0]
print("Baking finished...")
active = False
else:
print("Request denied, server busy...")
print("Data received: " + data.decode())
connection.send(('Callback from: ' + str(socket.gethostname())).encode())
connection.close()
print("Connection closed.")
sock.close()
print("Server closed.")

View File

@ -0,0 +1,50 @@
import bpy
from bpy.utils import register_class, unregister_class
from . import tlm, installopencv, imagetools
classes = [
tlm.TLM_BuildLightmaps,
tlm.TLM_CleanLightmaps,
tlm.TLM_ExploreLightmaps,
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,
tlm.TLM_AtlasListMoveItem,
tlm.TLM_PostAtlasListNewItem,
tlm.TLM_PostAtlastListDeleteItem,
tlm.TLM_PostAtlasListMoveItem,
tlm.TLM_StartServer,
tlm.TLM_BuildEnvironmentProbes,
tlm.TLM_CleanBuildEnvironmentProbes,
tlm.TLM_PrepareUVMaps,
tlm.TLM_LoadLightmaps,
tlm.TLM_DisableSpecularity,
tlm.TLM_DisableMetallic,
tlm.TLM_RemoveEmptyImages,
tlm.TLM_AddCollectionsPost,
tlm.TLM_AddSelectedCollectionsPost,
tlm.TLM_PostAtlasSpecialsMenu,
tlm.TLM_AddCollections,
tlm.TLM_AddSelectedCollections,
tlm.TLM_AtlasSpecialsMenu,
tlm.TLM_Reset,
tlm.TLM_CalcTexDex,
imagetools.TLM_ImageUpscale,
imagetools.TLM_ImageDownscale,
tlm.TLM_AddGLTFNode,
tlm.TLM_ShiftMultiplyLinks
]
def register():
for cls in classes:
register_class(cls)
def unregister():
for cls in classes:
unregister_class(cls)

View File

@ -0,0 +1,193 @@
import bpy, os, time, importlib
class TLM_ImageUpscale(bpy.types.Operator):
bl_idname = "tlm.image_upscale"
bl_label = "Upscale image"
bl_description = "Upscales the image to double resolution"
bl_options = {'REGISTER', 'UNDO'}
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'}
class TLM_ImageDownscale(bpy.types.Operator):
bl_idname = "tlm.image_downscale"
bl_label = "Downscale image"
bl_description = "Downscales the image to double resolution"
bl_options = {'REGISTER', 'UNDO'}
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 = 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

@ -0,0 +1,81 @@
import bpy, math, os, platform, subprocess, sys, re, shutil
def ShowMessageBox(message = "", title = "Message Box", icon = 'INFO'):
def draw(self, context):
self.layout.label(text=message)
bpy.context.window_manager.popup_menu(draw, title = title, icon = icon)
class TLM_Install_OpenCV(bpy.types.Operator):
"""Install OpenCV"""
bl_idname = "tlm.install_opencv_lightmaps"
bl_label = "Install OpenCV"
bl_description = "Install OpenCV"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
cycles = bpy.data.scenes[scene.name].cycles
print("Module OpenCV")
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")
else:
pythonlibpath = os.path.join(os.path.dirname(os.path.dirname(pythonbinpath)), "lib", os.path.basename(pythonbinpath))
ensurepippath = os.path.join(pythonlibpath, "ensurepip")
cmda = [pythonbinpath, ensurepippath, "--upgrade", "--user"]
pip = subprocess.run(cmda)
cmdc = [pythonbinpath, "-m", "pip", "install", "--upgrade", "pip"]
pipc = subprocess.run(cmdc)
if pip.returncode == 0:
print("Sucessfully installed pip!\n")
else:
try:
import pip
module_pip = True
except ImportError:
#pip
module_pip = False
if not module_pip:
print("Failed to install pip!\n")
if platform.system() == "Windows":
ShowMessageBox("Failed to install pip - Please start Blender as administrator", "Restart", 'PREFERENCES')
else:
ShowMessageBox("Failed to install pip - Try starting Blender with SUDO", "Restart", 'PREFERENCES')
return{'FINISHED'}
cmdb = [pythonbinpath, "-m", "pip", "install", "opencv-python"]
#opencv = subprocess.run(cmdb, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
opencv = subprocess.run(cmdb)
if opencv.returncode == 0:
print("Successfully installed OpenCV!\n")
else:
print("Failed to install OpenCV!\n")
if platform.system() == "Windows":
ShowMessageBox("Failed to install opencv - Please start Blender as administrator", "Restart", 'PREFERENCES')
else:
ShowMessageBox("Failed to install opencv - Try starting Blender with SUDO", "Restart", 'PREFERENCES')
return{'FINISHED'}
module_opencv = True
print("Sucessfully installed OpenCV!\n")
ShowMessageBox("Please restart blender to enable OpenCV filtering", "Restart", 'PREFERENCES')
return{'FINISHED'}

File diff suppressed because it is too large Load Diff

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,126 @@
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")
#If UV Packer installed
if "UV-Packer" in bpy.context.preferences.addons.keys():
row.prop(obj.TLM_ObjectProperties, "tlm_use_uv_packer")
if obj.TLM_ObjectProperties.tlm_use_uv_packer:
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_uv_packer_padding")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_uv_packer_packing_engine")
class TLM_PT_MaterialMenu(bpy.types.Panel):
bl_label = "The Lightmapper"
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,756 @@
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_Panel(bpy.types.Panel):
bl_label = "The Lightmapper"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
scene = context.scene
layout.use_property_split = True
layout.use_property_decorate = False
sceneProperties = scene.TLM_SceneProperties
class TLM_PT_Groups(bpy.types.Panel):
bl_label = "Lightmap Groups"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "TLM_PT_Panel"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.use_property_split = True
layout.use_property_decorate = False
sceneProperties = scene.TLM_SceneProperties
if sceneProperties.tlm_lightmap_engine == "Cycles":
rows = 2
#if len(atlasList) > 1:
# rows = 4
row = layout.row(align=True)
row.label(text="Lightmap Group List")
row = layout.row(align=True)
row.template_list("TLM_UL_GroupList", "Lightmap Groups", scene, "TLM_GroupList", scene, "TLM_GroupListItem", rows=rows)
col = row.column(align=True)
col.operator("tlm_atlaslist.new_item", icon='ADD', text="")
#col.operator("tlm_atlaslist.delete_item", icon='REMOVE', text="")
#col.menu("TLM_MT_AtlasListSpecials", icon='DOWNARROW_HLT', text="")
class TLM_PT_Settings(bpy.types.Panel):
bl_label = "Settings"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "LNX_PT_BakePanel"
@classmethod
def poll(self, context):
scene = context.scene
return scene.lnx_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)
row.prop(sceneProperties, "tlm_apply_modifiers")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_keep_baked_files")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_repartition_on_clean")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_save_preprocess_lightmaps")
row = layout.row(align=True)
try:
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 = "LNX_PT_BakePanel"
@classmethod
def poll(self, context):
scene = context.scene
return scene.lnx_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 = "LNX_PT_BakePanel"
@classmethod
def poll(self, context):
scene = context.scene
return scene.lnx_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 = "LNX_PT_BakePanel"
@classmethod
def poll(self, context):
scene = context.scene
return scene.lnx_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_decoder_setup:
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_split_premultiplied")
if sceneProperties.tlm_encoding_mode_b == "HDR":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_format")
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 = "LNX_PT_BakePanel"
@classmethod
def poll(self, context):
scene = context.scene
return scene.lnx_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.prop(sceneProperties, "tlm_utility_context")
row = layout.row(align=True)
if sceneProperties.tlm_utility_context == "SetBatching":
row.operator("tlm.enable_set")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_utility_set")
row = layout.row(align=True)
#row.label(text="ABCD")
row.prop(sceneProperties, "tlm_mesh_lightmap_unwrap_mode")
if sceneProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if scene.TLM_AtlasListItem >= 0 and len(scene.TLM_AtlasList) > 0:
row = layout.row()
item = scene.TLM_AtlasList[scene.TLM_AtlasListItem]
row.prop_search(sceneProperties, "tlm_atlas_pointer", scene, "TLM_AtlasList", text='Atlas Group')
else:
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
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")
elif sceneProperties.tlm_utility_context == "EnvironmentProbes":
row.label(text="Environment Probes")
row = layout.row()
row.operator("tlm.build_environmentprobe")
row = layout.row()
row.operator("tlm.clean_environmentprobe")
row = layout.row()
row.prop(sceneProperties, "tlm_environment_probe_engine")
row = layout.row()
row.prop(sceneProperties, "tlm_cmft_path")
row = layout.row()
row.prop(sceneProperties, "tlm_environment_probe_resolution")
row = layout.row()
row.prop(sceneProperties, "tlm_create_spherical")
if sceneProperties.tlm_create_spherical:
row = layout.row()
row.prop(sceneProperties, "tlm_invert_direction")
row = layout.row()
row.prop(sceneProperties, "tlm_write_sh")
row = layout.row()
row.prop(sceneProperties, "tlm_write_radiance")
elif sceneProperties.tlm_utility_context == "LoadLightmaps":
row = layout.row(align=True)
row.label(text="Load lightmaps")
row = layout.row()
row.prop(sceneProperties, "tlm_load_folder")
row = layout.row()
row.operator("tlm.load_lightmaps")
row = layout.row()
row.prop(sceneProperties, "tlm_load_atlas")
elif sceneProperties.tlm_utility_context == "MaterialAdjustment":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_utility_set")
row = layout.row(align=True)
row.operator("tlm.disable_specularity")
row.operator("tlm.disable_metallic")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_remove_met_spec_link")
row = layout.row(align=True)
row.operator("tlm.remove_empty_images")
row = layout.row(align=True)
elif sceneProperties.tlm_utility_context == "NetworkRender":
row.label(text="Network Rendering")
row = layout.row()
row.operator("tlm.start_server")
layout.label(text="Atlas Groups")
elif sceneProperties.tlm_utility_context == "TexelDensity":
row.label(text="Texel Density Utilies")
row = layout.row()
elif sceneProperties.tlm_utility_context == "GLTFUtil":
row.label(text="GLTF material utilities")
row = layout.row()
row.operator("tlm.add_gltf_node")
row = layout.row()
row.operator("tlm.shift_multiply_links")
class TLM_PT_Selection(bpy.types.Panel):
bl_label = "Selection"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "LNX_PT_BakePanel"
@classmethod
def poll(self, context):
scene = context.scene
return scene.lnx_bakemode == "Lightmap"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.use_property_split = True
layout.use_property_decorate = False
sceneProperties = scene.TLM_SceneProperties
row = layout.row(align=True)
row.operator("tlm.enable_selection")
row = layout.row(align=True)
row.operator("tlm.disable_selection")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_override_object_settings")
if sceneProperties.tlm_override_object_settings:
row = layout.row(align=True)
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_lightmap_unwrap_mode")
row = layout.row()
if sceneProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if scene.TLM_AtlasListItem >= 0 and len(scene.TLM_AtlasList) > 0:
row = layout.row()
item = scene.TLM_AtlasList[scene.TLM_AtlasListItem]
row.prop_search(sceneProperties, "tlm_atlas_pointer", scene, "TLM_AtlasList", text='Atlas Group')
else:
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
else:
row = layout.row()
row.prop(sceneProperties, "tlm_postpack_object")
row = layout.row()
if sceneProperties.tlm_postpack_object and sceneProperties.tlm_mesh_lightmap_unwrap_mode != "AtlasGroupA":
if scene.TLM_PostAtlasListItem >= 0 and len(scene.TLM_PostAtlasList) > 0:
row = layout.row()
item = scene.TLM_PostAtlasList[scene.TLM_PostAtlasListItem]
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)
# for addon in bpy.context.preferences.addons.keys():
# if addon.startswith("Texel_Density"):
# row.operator("tlm.toggle_texel_density")
# row = layout.row(align=True)
class TLM_PT_Additional(bpy.types.Panel):
bl_label = "Additional"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "LNX_PT_BakePanel"
@classmethod
def poll(self, context):
scene = context.scene
return scene.lnx_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
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("TLM_MT_AtlasListSpecials", icon='DOWNARROW_HLT', 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))
layout.prop(item, "tlm_atlas_merge_samemat")
layout.prop(item, "tlm_use_uv_packer")
layout.prop(item, "tlm_uv_packer_padding")
layout.prop(item, "tlm_uv_packer_packing_engine")
else:
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="")
col.menu("TLM_MT_PostAtlasListSpecials", icon='DOWNARROW_HLT', 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,106 @@
import bpy, platform
from os.path import basename, dirname
from bpy.types import AddonPreferences
from bpy.props import *
from .. operators import installopencv
from . import addon_preferences
import importlib
class TLM_AddonPreferences(AddonPreferences):
bl_idname = __name__.split(".")[0]
tlm_ui_mode: EnumProperty(
items=[('simple', 'Simple', 'Simple UI'),
('advanced', 'Advanced', 'Advanced UI')],
name='UI mode', default='simple', description='Choose UI mode')
def draw(self, context):
layout = self.layout
box = layout.box()
row = box.row()
row.label(text="UI Mode")
row.prop(self, "tlm_ui_mode")
row = box.row()
row.label(text="Simple: Only the basic setup for Blender/Eevee baking with non-experimental features.")
row = box.row()
row.label(text="Full set of options available.")
row = box.row()
row.label(text="OpenCV")
cv2 = importlib.util.find_spec("cv2")
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")
uvpacker_addon = False
for addon in bpy.context.preferences.addons.keys():
if addon.startswith("UV-Packer"):
uvpacker_addon = True
box = layout.box()
row = box.row()
row.label(text="UV Packer")
if uvpacker_addon:
row.label(text="UV Packer installed and available")
else:
row.label(text="UV Packer not installed", icon_value=2)
row = box.row()
row.label(text="Github: https://www.uv-packer.com/blender/")
texel_density_addon = False
for addon in bpy.context.preferences.addons.keys():
if addon.startswith("Texel_Density"):
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

@ -0,0 +1,62 @@
import bpy
from bpy.utils import register_class, unregister_class
from . import scene, object, atlas, image
from . renderer import cycles, luxcorerender, octanerender
from . denoiser import oidn, optix
classes = [
scene.TLM_SceneProperties,
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,
image.TLM_ImageProperties,
scene.TLM_UL_GroupList,
scene.TLM_GroupListItem
]
def register():
for cls in classes:
register_class(cls)
bpy.types.Scene.TLM_SceneProperties = bpy.props.PointerProperty(type=scene.TLM_SceneProperties)
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.Scene.TLM_GroupListItem = bpy.props.IntProperty(name="Index for my_list", default=0)
bpy.types.Scene.TLM_GroupList = bpy.props.CollectionProperty(type=scene.TLM_GroupListItem)
bpy.types.Material.TLM_ignore = bpy.props.BoolProperty(name="Skip material", description="Ignore material for lightmapped object", default=False)
def unregister():
for cls in classes:
unregister_class(cls)
del bpy.types.Scene.TLM_SceneProperties
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.Image.TLM_ImageProperties
del bpy.types.Scene.TLM_GroupListItem
del bpy.types.Scene.TLM_GroupList

View File

@ -0,0 +1,166 @@
import bpy
from bpy.props import *
class TLM_PostAtlasListItem(bpy.types.PropertyGroup):
obj: PointerProperty(type=bpy.types.Object, description="The object to bake")
tlm_atlas_lightmap_resolution : EnumProperty(
items = [('32', '32', 'TODO'),
('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO'),
('8192', '8192', 'TODO')],
name = "Atlas Lightmap Resolution",
description="TODO",
default='256')
tlm_atlas_repack_on_cleanup : BoolProperty(
name="Repack on cleanup",
description="Postpacking adjusts the UV's. Toggle to resize back to full scale on cleanup.",
default=True)
tlm_atlas_dilation : BoolProperty(
name="Dilation",
description="Adds a blurred background layer that acts as a dilation map.",
default=False)
tlm_atlas_unwrap_margin : FloatProperty(
name="Unwrap Margin",
default=0.1,
min=0.0,
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_merge_samemat : BoolProperty(
name="Merge materials",
description="Merge objects with same materials.",
default=True)
tlm_postatlas_lightmap_unwrap_mode : EnumProperty(
items = unwrap_modes,
name = "Unwrap Mode",
description="Atlas unwrapping method",
default='SmartProject')
class TLM_UL_PostAtlasList(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
custom_icon = 'OBJECT_DATAMODE'
if self.layout_type in {'DEFAULT', 'COMPACT'}:
#In list object counter
amount = 0
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
row = layout.row()
row.prop(item, "name", text="", emboss=False, icon=custom_icon)
col = row.column()
col.label(text=item.tlm_atlas_lightmap_resolution)
col = row.column()
col.alignment = 'RIGHT'
col.label(text=str(amount))
elif self.layout_type in {'GRID'}:
layout.alignment = 'CENTER'
layout.label(text="", icon = custom_icon)
class TLM_AtlasListItem(bpy.types.PropertyGroup):
obj: PointerProperty(type=bpy.types.Object, description="The object to bake")
tlm_atlas_lightmap_resolution : EnumProperty(
items = [('32', '32', 'TODO'),
('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO'),
('8192', '8192', 'TODO')],
name = "Atlas Lightmap Resolution",
description="TODO",
default='256')
tlm_atlas_unwrap_margin : FloatProperty(
name="Unwrap Margin",
default=0.1,
min=0.0,
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 = unwrap_modes,
name = "Unwrap Mode",
description="Atlas unwrapping method",
default='SmartProject')
tlm_atlas_merge_samemat : BoolProperty(
name="Merge materials",
description="Merge objects with same materials.",
default=True)
tlm_use_uv_packer : BoolProperty(
name="Use UV Packer",
description="UV Packer will be utilized after initial UV mapping for optimized packing.",
default=False)
tlm_uv_packer_padding : FloatProperty(
name="Padding",
default=2.0,
min=0.0,
max=100.0,
subtype='FACTOR')
tlm_uv_packer_packing_engine : EnumProperty(
items = [('OP0', 'Efficient', 'Best compromise for speed and space usage.'),
('OP1', 'High Quality', 'Slowest, but maximum space usage.')],
name = "Packing Engine",
description="Which UV Packer engine to use.",
default='OP0')
class TLM_UL_AtlasList(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
custom_icon = 'OBJECT_DATAMODE'
if self.layout_type in {'DEFAULT', 'COMPACT'}:
amount = 0
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if obj.TLM_ObjectProperties.tlm_atlas_pointer == item.name:
amount = amount + 1
row = layout.row()
row.prop(item, "name", text="", emboss=False, icon=custom_icon)
col = row.column()
col.label(text=item.tlm_atlas_lightmap_resolution)
col = row.column()
col.alignment = 'RIGHT'
col.label(text=str(amount))
elif self.layout_type in {'GRID'}:
layout.alignment = 'CENTER'
layout.label(text="", icon = custom_icon)

View File

@ -0,0 +1,4 @@
import bpy
from bpy.props import *
class TLM_IntegratedDenoiseEngineProperties(bpy.types.PropertyGroup):

View File

@ -0,0 +1,40 @@
import bpy, os
from ...utility import utility
from bpy.props import *
class TLM_OIDNEngineProperties(bpy.types.PropertyGroup):
tlm_oidn_path : StringProperty(
name="OIDN Path",
description="The path to the OIDN binaries",
default="",
subtype="FILE_PATH")
tlm_oidn_verbose : BoolProperty(
name="Verbose",
description="TODO")
tlm_oidn_threads : IntProperty(
name="Threads",
default=0,
min=0,
max=64,
description="Amount of threads to use. Set to 0 for auto-detect.")
tlm_oidn_maxmem : IntProperty(
name="Tiling max Memory",
default=0,
min=512,
max=32768,
description="Use tiling for memory conservation. Set to 0 to disable tiling.")
tlm_oidn_affinity : BoolProperty(
name="Set Affinity",
description="TODO")
tlm_oidn_use_albedo : BoolProperty(
name="Use albedo map",
description="TODO")
tlm_oidn_use_normal : BoolProperty(
name="Use normal map",
description="TODO")

View File

@ -0,0 +1,21 @@
import bpy
from bpy.props import *
class TLM_OptixEngineProperties(bpy.types.PropertyGroup):
tlm_optix_path : StringProperty(
name="Optix Path",
description="TODO",
default="",
subtype="FILE_PATH")
tlm_optix_verbose : BoolProperty(
name="Verbose",
description="TODO")
tlm_optix_maxmem : IntProperty(
name="Tiling max Memory",
default=0,
min=512,
max=32768,
description="Use tiling for memory conservation. Set to 0 to disable tiling.")

View File

@ -0,0 +1,4 @@
import bpy
from bpy.props import *
class TLM_FilteringProperties(bpy.types.PropertyGroup):

View File

@ -0,0 +1,26 @@
import bpy
from bpy.props import *
class TLM_ImageProperties(bpy.types.PropertyGroup):
tlm_image_scale_engine : EnumProperty(
items = [('OpenCV', 'OpenCV', 'TODO')],
name = "Scaling engine",
description="TODO",
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

@ -0,0 +1,182 @@
import bpy
from bpy.props import *
class TLM_ObjectProperties(bpy.types.PropertyGroup):
addon_keys = bpy.context.preferences.addons.keys()
tlm_atlas_pointer : StringProperty(
name = "Atlas Group",
description = "",
default = "")
tlm_postatlas_pointer : StringProperty(
name = "Atlas Group",
description = "Atlas Lightmap Group",
default = "")
tlm_uvchannel_pointer : StringProperty(
name = "UV Channel",
description = "Select UV Channel to bake to",
default = "")
tlm_uvchannel_pointer : BoolProperty(
name="Enable Lightmapping",
description="TODO",
default=False)
tlm_mesh_lightmap_use : BoolProperty(
name="Enable Lightmapping",
description="TODO",
default=False)
tlm_material_ignore : BoolProperty(
name="Skip material",
description="Ignore material for lightmapped object",
default=False)
tlm_mesh_lightmap_resolution : EnumProperty(
items = [('32', '32', 'TODO'),
('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO'),
('8192', '8192', 'TODO')],
name = "Lightmap Resolution",
description="TODO",
default='256')
unwrap_modes = [('Lightmap', 'Lightmap', 'TODO'),
('SmartProject', 'Smart Project', 'TODO'),
('AtlasGroupA', 'Atlas Group (Prepack)', 'Attaches the object to a prepack Atlas group. Will overwrite UV map on build.'),
('Copy', 'Copy existing', 'Use the existing UV channel')]
tlm_postpack_object : BoolProperty( #CHECK INSTEAD OF ATLASGROUPB
name="Postpack object",
description="Postpack object into an AtlasGroup",
default=False)
if "blender_xatlas" in addon_keys:
unwrap_modes.append(('Xatlas', 'Xatlas', 'TODO'))
tlm_mesh_lightmap_unwrap_mode : EnumProperty(
items = unwrap_modes,
name = "Unwrap Mode",
description="TODO",
default='SmartProject')
tlm_mesh_unwrap_margin : FloatProperty(
name="Unwrap Margin",
default=0.1,
min=0.0,
max=1.0,
subtype='FACTOR')
tlm_mesh_filter_override : BoolProperty(
name="Override filtering",
description="Override the scene specific filtering",
default=False)
#FILTERING SETTINGS GROUP
tlm_mesh_filtering_engine : EnumProperty(
items = [('OpenCV', 'OpenCV', 'Make use of OpenCV based image filtering (Requires it to be installed first in the preferences panel)'),
('Numpy', 'Numpy', 'Make use of Numpy based image filtering (Integrated)')],
name = "Filtering library",
description="Select which filtering library to use.",
default='Numpy')
#Numpy Filtering options
tlm_mesh_numpy_filtering_mode : EnumProperty(
items = [('Blur', 'Blur', 'Basic blur filtering.')],
name = "Filter",
description="TODO",
default='Blur')
#OpenCV Filtering options
tlm_mesh_filtering_mode : EnumProperty(
items = [('Box', 'Box', 'Basic box blur'),
('Gaussian', 'Gaussian', 'Gaussian blurring'),
('Bilateral', 'Bilateral', 'Edge-aware filtering'),
('Median', 'Median', 'Median blur')],
name = "Filter",
description="TODO",
default='Median')
tlm_mesh_filtering_gaussian_strength : IntProperty(
name="Gaussian Strength",
default=3,
min=1,
max=50)
tlm_mesh_filtering_iterations : IntProperty(
name="Filter Iterations",
default=5,
min=1,
max=50)
tlm_mesh_filtering_box_strength : IntProperty(
name="Box Strength",
default=1,
min=1,
max=50)
tlm_mesh_filtering_bilateral_diameter : IntProperty(
name="Pixel diameter",
default=3,
min=1,
max=50)
tlm_mesh_filtering_bilateral_color_deviation : IntProperty(
name="Color deviation",
default=75,
min=1,
max=100)
tlm_mesh_filtering_bilateral_coordinate_deviation : IntProperty(
name="Color deviation",
default=75,
min=1,
max=100)
tlm_mesh_filtering_median_kernel : IntProperty(
name="Median kernel",
default=3,
min=1,
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")
tlm_use_uv_packer : BoolProperty(
name="Use UV Packer",
description="UV Packer will be utilized after initial UV mapping for optimized packing.",
default=False)
tlm_uv_packer_padding : FloatProperty(
name="Padding",
default=2.0,
min=0.0,
max=100.0,
subtype='FACTOR')
tlm_uv_packer_packing_engine : EnumProperty(
items = [('OP0', 'Efficient', 'Best compromise for speed and space usage.'),
('OP1', 'High Quality', 'Slowest, but maximum space usage.')],
name = "Packing Engine",
description="Which UV Packer engine to use.",
default='OP0')
#Padding
#Type
#Rescale
#Pre-rotate

View File

@ -0,0 +1,115 @@
import bpy
from bpy.props import *
class TLM_CyclesSceneProperties(bpy.types.PropertyGroup):
tlm_mode : EnumProperty(
items = [('CPU', 'CPU', 'Use the processor to bake textures'),
('GPU', 'GPU', 'Use the graphics card to bake textures')],
name = "Device",
description="Select whether to use the CPU or the GPU for baking",
default="CPU")
tlm_quality : EnumProperty(
items = [('0', 'Exterior Preview', 'Best for fast exterior previz'),
('1', 'Interior Preview', 'Best for fast interior previz with bounces'),
('2', 'Medium', 'Best for complicated interior preview and final for isometric environments'),
('3', 'High', 'Best used for final baking for 3rd person games'),
('4', 'Production', 'Best for first-person and Archviz'),
('5', 'Custom', 'Uses the cycles sample settings provided the user')],
name = "Quality",
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'),
('4', '1/4', '4'),
('8', '1/8', '8')],
name = "Resolution scale",
description="Select resolution scale",
default="2")
tlm_setting_supersample : EnumProperty(
items = [('none', 'None', 'No supersampling'),
('2x', '2x', 'Double supersampling'),
('4x', '4x', 'Quadruple supersampling')],
name = "Supersampling",
description="Supersampling scale",
default="none")
tlm_bake_mode : EnumProperty(
items = [('Background', 'Background', 'More overhead; allows for network.'),
('Foreground', 'Foreground', 'Direct in-session bake')],
name = "Baking mode",
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 = caching_modes,
name = "Caching mode",
description="Select cache mode",
default="Copy")
tlm_directional_mode : EnumProperty(
items = [('None', 'None', 'No directional information'),
('Normal', 'Baked normal', 'Baked normal maps are taken into consideration')],
name = "Directional mode",
description="Select directional mode",
default="None")
tlm_lightmap_savedir : StringProperty(
name="Lightmap Directory",
description="TODO",
default="Lightmaps",
subtype="FILE_PATH")
tlm_dilation_margin : IntProperty(
name="Dilation margin",
default=4,
min=1,
max=64,
subtype='PIXEL')
tlm_exposure_multiplier : FloatProperty(
name="Exposure Multiplier",
default=0,
description="0 to disable. Multiplies GI value")
tlm_metallic_handling_mode : EnumProperty(
items = [('ignore', 'Ignore', 'No directional information'),
('clamp', 'Clamp', 'Clamp to value 0.9'),
('zero', 'Zero', 'Temporarily set to 0 during baking, and reapply after')],
name = "Metallic handling",
description="Set metallic handling mode to prevent black-baking.",
default="ignore")
tlm_lighting_mode : EnumProperty(
items = [('combined', 'Combined', 'Bake combined lighting'),
('combinedao', 'Combined+AO', 'Bake combined lighting with Ambient Occlusion'),
('indirect', 'Indirect', 'Bake indirect lighting'),
('indirectao', 'Indirect+AO', 'Bake indirect lighting with Ambient Occlusion'),
('ao', 'AO', 'Bake only Ambient Occlusion'),
('complete', 'Complete', 'Bake complete map')],
name = "Lighting mode",
description="TODO.",
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,11 @@
import bpy
from bpy.props import *
class TLM_LuxCoreSceneProperties(bpy.types.PropertyGroup):
#Luxcore specific here
tlm_luxcore_dir : StringProperty(
name="Luxcore Directory",
description="Standalone path to your LuxCoreRender binary.",
default="",
subtype="FILE_PATH")

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

@ -0,0 +1,585 @@
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(('OctaneRender', 'Octane Render', 'Use Octane Render for lightmapping'))
tlm_atlas_pointer : StringProperty(
name = "Atlas Group",
description = "Atlas Lightmap Group",
default = "")
tlm_postatlas_pointer : StringProperty(
name = "Atlas Group",
description = "Atlas Lightmap Group",
default = "")
tlm_lightmap_engine : EnumProperty(
items = engines,
name = "Lightmap Engine",
description="Select which lightmap engine to use.",
default='Cycles')
#SETTINGS GROUP
tlm_setting_clean_option : EnumProperty(
items = [('Clean', 'Full Clean', 'Clean lightmap directory and revert all materials'),
('CleanMarked', 'Clean marked', 'Clean only the objects marked for lightmapping')],
name = "Clean mode",
description="The cleaning mode, either full or partial clean. Be careful that you don't delete lightmaps you don't intend to delete.",
default='Clean')
tlm_setting_keep_cache_files : BoolProperty(
name="Keep cache files",
description="Keep cache files (non-filtered and non-denoised)",
default=True)
tlm_keep_baked_files : BoolProperty(
name="Keep bake files",
description="Keep the baked lightmap files when cleaning",
default=False)
tlm_repartition_on_clean : BoolProperty(
name="Repartition on clean",
description="Repartition material names on clean",
default=False)
tlm_setting_renderer : EnumProperty(
items = [('CPU', 'CPU', 'Bake using the processor'),
('GPU', 'GPU', 'Bake using the graphics card')],
name = "Device",
description="Select whether to use the CPU or the GPU",
default="CPU")
tlm_setting_scale : EnumProperty(
items = [('8', '1/8', '1/8th of set scale'),
('4', '1/4', '1/4th of set scale'),
('2', '1/2', 'Half of set scale'),
('1', '1/1', 'Full scale')],
name = "Lightmap Resolution scale",
description="Lightmap resolution scaling. Adjust for previewing.",
default="1")
tlm_setting_supersample : EnumProperty(
items = [('2x', '2x', 'Double the sampling resolution'),
('4x', '4x', 'Quadruple the sampling resolution')],
name = "Lightmap Supersampling",
description="Supersamples the baked lightmap. Increases bake time",
default="2x")
tlm_setting_savedir : StringProperty(
name="Lightmap Directory",
description="Your baked lightmaps will be stored here.",
default="Lightmaps",
subtype="FILE_PATH")
tlm_setting_exposure_multiplier : FloatProperty(
name="Exposure Multiplier",
default=0,
description="0 to disable. Multiplies GI value")
tlm_alert_on_finish : BoolProperty(
name="Alert on finish",
description="Play a sound when the lightmaps are done.",
default=False)
tlm_setting_apply_scale : BoolProperty(
name="Apply scale",
description="Apply the scale before unwrapping.",
default=True)
tlm_play_sound : BoolProperty(
name="Play sound on finish",
description="Play sound on finish",
default=False)
tlm_compile_statistics : BoolProperty(
name="Compile statistics",
description="Compile time statistics in the lightmap folder.",
default=True)
tlm_apply_on_unwrap : BoolProperty(
name="Apply scale",
description="TODO",
default=False)
tlm_save_preprocess_lightmaps : BoolProperty(
name="Save preprocessed lightmaps",
description="TODO",
default=False)
#DENOISE SETTINGS GROUP
tlm_denoise_use : BoolProperty(
name="Enable denoising",
description="Enable denoising for lightmaps",
default=False)
tlm_denoise_engine : EnumProperty(
items = [('Integrated', 'Integrated', 'Use the Blender native denoiser (Compositor; Slow)'),
('OIDN', 'Intel Denoiser', 'Use Intel denoiser (CPU powered)'),
('Optix', 'Optix Denoiser', 'Use Nvidia Optix denoiser (GPU powered)')],
name = "Denoiser",
description="Select which denoising engine to use.",
default='Integrated')
#FILTERING SETTINGS GROUP
tlm_filtering_use : BoolProperty(
name="Enable denoising",
description="Enable denoising for lightmaps",
default=False)
tlm_filtering_engine : EnumProperty(
items = [('OpenCV', 'OpenCV', 'Make use of OpenCV based image filtering (Requires it to be installed first in the preferences panel)'),
('Shader', 'Shader', 'Make use of GPU offscreen shader to filter')],
name = "Filtering library",
description="Select which filtering library to use.",
default='OpenCV')
#Numpy Filtering options
tlm_numpy_filtering_mode : EnumProperty(
items = [('Blur', 'Blur', 'Basic blur filtering.')],
name = "Filter",
description="TODO",
default='Blur')
#OpenCV Filtering options
tlm_filtering_mode : EnumProperty(
items = [('Box', 'Box', 'Basic box blur'),
('Gaussian', 'Gaussian', 'Gaussian blurring'),
('Bilateral', 'Bilateral', 'Edge-aware filtering'),
('Median', 'Median', 'Median blur')],
name = "Filter",
description="TODO",
default='Median')
tlm_filtering_gaussian_strength : IntProperty(
name="Gaussian Strength",
default=3,
min=1,
max=50)
tlm_filtering_iterations : IntProperty(
name="Filter Iterations",
default=5,
min=1,
max=50)
tlm_filtering_box_strength : IntProperty(
name="Box Strength",
default=1,
min=1,
max=50)
tlm_filtering_bilateral_diameter : IntProperty(
name="Pixel diameter",
default=3,
min=1,
max=50)
tlm_filtering_bilateral_color_deviation : IntProperty(
name="Color deviation",
default=75,
min=1,
max=100)
tlm_filtering_bilateral_coordinate_deviation : IntProperty(
name="Coordinate deviation",
default=75,
min=1,
max=100)
tlm_filtering_median_kernel : IntProperty(
name="Median kernel",
default=3,
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",
description="Enable encoding for lightmaps",
default=False)
tlm_encoding_device : EnumProperty(
items = [('CPU', 'CPU', 'Todo'),
('GPU', 'GPU', 'Todo.')],
name = "Encoding Device",
description="TODO",
default='CPU')
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.'),
('SDR', 'SDR', '8-bit flat encoding.')]
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.'),
('SDR', 'SDR', '8-bit flat encoding.')]
tlm_encoding_mode_a : EnumProperty(
items = encoding_modes_1,
name = "Encoding Mode",
description="TODO",
default='HDR')
tlm_encoding_mode_b : EnumProperty(
items = encoding_modes_2,
name = "Encoding Mode",
description="RGBE 32-bit Radiance HDR File",
default='HDR')
tlm_encoding_range : IntProperty(
name="Encoding range",
description="Higher gives a larger HDR range, but also gives more banding.",
default=6,
min=1,
max=255)
tlm_decoder_setup : BoolProperty(
name="Use decoder",
description="Apply a node for decoding.",
default=False)
tlm_split_premultiplied : BoolProperty(
name="Split for premultiplied",
description="Some game engines doesn't support non-premultiplied files. This splits the alpha channel to a separate file.",
default=False)
tlm_encoding_colorspace : EnumProperty(
items = [('XYZ', 'XYZ', 'TODO'),
('sRGB', 'sRGB', 'TODO'),
('NonColor', 'Non-Color', 'TODO'),
('ACES', 'Linear ACES', 'TODO'),
('Linear', 'Linear', 'TODO'),
('FilmicLog', 'Filmic Log', 'TODO')],
name = "Color Space",
description="TODO",
default='Linear')
tlm_compression : IntProperty(
name="PNG Compression",
description="0 = No compression. 100 = Maximum compression.",
default=0,
min=0,
max=100)
tlm_format : EnumProperty(
items = [('RGBE', 'HDR', '32-bit RGBE encoded .hdr files. No compression available.'),
('EXR', 'EXR', '32-bit OpenEXR format.')],
name = "Format",
description="Select default 32-bit format",
default='RGBE')
tlm_override_object_settings : BoolProperty(
name="Override settings",
description="TODO",
default=False)
tlm_mesh_lightmap_resolution : EnumProperty(
items = [('32', '32', 'TODO'),
('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO'),
('8192', '8192', 'TODO')],
name = "Lightmap Resolution",
description="TODO",
default='256')
tlm_mesh_lightmap_unwrap_mode : EnumProperty(
items = [('Lightmap', 'Lightmap', 'TODO'),
('SmartProject', 'Smart Project', 'TODO'),
('AtlasGroupA', 'Atlas Group (Prepack)', 'Attaches the object to a prepack Atlas group. Will overwrite UV map on build.'),
('Xatlas', 'Xatlas', 'TODO')],
name = "Unwrap Mode",
description="TODO",
default='SmartProject')
tlm_postpack_object : BoolProperty( #CHECK INSTEAD OF ATLASGROUPB
name="Postpack object",
description="Postpack object into an AtlasGroup",
default=False)
tlm_mesh_unwrap_margin : FloatProperty(
name="Unwrap Margin",
default=0.1,
min=0.0,
max=1.0,
subtype='FACTOR')
tlm_headless : BoolProperty(
name="Don't apply materials",
description="Headless; Do not apply baked materials on finish.",
default=False)
tlm_atlas_mode : EnumProperty(
items = [('Prepack', 'Pre-packing', 'Todo.'),
('Postpack', 'Post-packing', 'Todo.')],
name = "Atlas mode",
description="TODO",
default='Prepack')
tlm_alert_sound : EnumProperty(
items = [('dash', 'Dash', 'Dash alert'),
('noot', 'Noot', 'Noot alert'),
('gentle', 'Gentle', 'Gentle alert'),
('pingping', 'Ping', 'Ping alert')],
name = "Alert sound",
description="Alert sound when lightmap building finished.",
default="gentle")
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",
default=False)
tlm_compile_statistics : BoolProperty(
name="Compile statistics",
description="Compile lightbuild statistics",
default=False)
tlm_override_bg_color : BoolProperty(
name="Override background",
description="Override background color, black by default.",
default=False)
tlm_override_color : FloatVectorProperty(name="Color",
description="Background color for baked maps",
subtype='COLOR',
default=[0.5,0.5,0.5])
tlm_reset_uv : BoolProperty(
name="Remove Lightmap UV",
description="Remove existing UV maps for lightmaps.",
default=False)
tlm_apply_modifiers : BoolProperty(
name="Apply modifiers",
description="Apply all modifiers to objects.",
default=True)
tlm_batch_mode : BoolProperty(
name="Batch mode",
description="Batch collections.",
default=False)
tlm_network_render : BoolProperty(
name="Enable network rendering",
description="Enable network rendering (Unstable).",
default=False)
tlm_network_paths : PointerProperty(
name="Network file",
description="Network instruction file",
type=bpy.types.Text)
tlm_network_dir : StringProperty(
name="Network directory",
description="Use a path that is accessible to all your network render devices.",
default="",
subtype="FILE_PATH")
tlm_cmft_path : StringProperty(
name="CMFT Path",
description="The path to the CMFT binaries",
default="",
subtype="FILE_PATH")
tlm_create_spherical : BoolProperty(
name="Create spherical texture",
description="Merge cubemap to a 360 spherical texture.",
default=False)
tlm_write_sh : BoolProperty(
name="Calculate SH coefficients",
description="Calculates spherical harmonics coefficients to a file.",
default=False)
tlm_write_radiance : BoolProperty(
name="Write radiance images",
description="Writes out the radiance images.",
default=False)
tlm_invert_direction : BoolProperty(
name="Invert direction",
description="Inverts the direction.",
default=False)
tlm_environment_probe_resolution : EnumProperty(
items = [('32', '32', 'TODO'),
('64', '64', 'TODO'),
('128', '128', 'TODO'),
('256', '256', 'TODO'),
('512', '512', 'TODO'),
('1024', '1024', 'TODO'),
('2048', '2048', 'TODO'),
('4096', '4096', 'TODO'),
('8192', '8192', 'TODO')],
name = "Probe Resolution",
description="TODO",
default='256')
tlm_environment_probe_engine : EnumProperty(
items = [('BLENDER_EEVEE', 'Eevee', 'TODO'),
('CYCLES', 'Cycles', 'TODO')],
name = "Probe Render Engine",
description="TODO",
default='BLENDER_EEVEE')
tlm_load_folder : StringProperty(
name="Load Folder",
description="Load existing lightmaps from folder",
subtype="DIR_PATH")
tlm_load_atlas : BoolProperty(
name="Load lightmaps based on atlas sets",
description="Use the current Atlas list.",
default=False)
tlm_utility_set : EnumProperty(
items = [('Scene', 'Scene', 'Set for all objects in the scene.'),
('Selection', 'Selection', 'Set for selected objects.'),
('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')
tlm_remove_met_spec_link : BoolProperty(
name="Remove image link",
description="Removes the connected node on metallic or specularity set disable",
default=False)
tlm_utility_context : EnumProperty(
items = [('SetBatching', 'Set Batching', 'Set batching options. Allows to set lightmap options for multiple objects.'),
('EnvironmentProbes', 'Environment Probes', 'Options for rendering environment probes. Cubemaps and panoramic HDRs for external engines'),
('LoadLightmaps', 'Load Lightmaps', 'Options for loading pre-built lightmaps.'),
('NetworkRender', 'Network Rendering', 'Distribute lightmap building across multiple machines.'),
('MaterialAdjustment', 'Material Adjustment', 'Allows adjustment of multiple materials at once.'),
('TexelDensity', 'Texel Density', 'Allows setting texel densities of the UV.'),
('GLTFUtil', 'GLTF Utilities', 'GLTF related material utilities.')],
name = "Utility Context",
description="Set Utility Context",
default='SetBatching')
tlm_addon_uimode : EnumProperty(
items = [('Simple', 'Simple', 'TODO'),
('Advanced', 'Advanced', 'TODO')],
name = "UI Mode",
description="TODO",
default='Simple')
class TLM_GroupListItem(bpy.types.PropertyGroup):
obj: PointerProperty(type=bpy.types.Object, description="The object to bake")
class TLM_UL_GroupList(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
custom_icon = 'OBJECT_DATAMODE'
if self.layout_type in {'DEFAULT', 'COMPACT'}:
amount = 0
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
if obj.TLM_ObjectProperties.tlm_atlas_pointer == item.name:
amount = amount + 1
row = layout.row()
row.prop(item, "name", text="", emboss=False, icon=custom_icon)
col = row.column()
col.label(text=item.tlm_atlas_lightmap_resolution)
col = row.column()
col.alignment = 'RIGHT'
col.label(text=str(amount))
elif self.layout_type in {'GRID'}:
layout.alignment = 'CENTER'
layout.label(text="", icon = custom_icon)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,124 @@
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()
dup.name = "." + material.name + "_Original"
dup.use_fake_user = True
def backup_material_cache(slot, path):
bpy.ops.wm.save_as_mainfile(filepath=path, copy=True)
def backup_material_cache_restore(slot, path):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Restore cache")
# def backup_material_restore(obj): #??
# if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
# print("Restoring material for: " + obj.name)
#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 no:
# - In which cases are there not?
# - If a lightmapped material was applied to a non-lightmap object?
# 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)
if "TLM_PrevMatArray" in obj:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Material restore array found: " + str(obj["TLM_PrevMatArray"]))
#Running through the slots
prevMatArray = obj["TLM_PrevMatArray"]
slotsLength = len(prevMatArray)
if len(prevMatArray) > 0:
for idx, slot in enumerate(obj.material_slots): #For each slot, we get the index
#We only need the index, corresponds to the array index
try:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Attempting to set material")
originalMaterial = prevMatArray[idx]
except IndexError:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Material restore failed - Resetting")
originalMaterial = ""
if slot.material is not None:
#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
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

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

View File

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

View File

@ -0,0 +1,947 @@
import bpy, math, time
from . import cache
from .. utility import *
def assemble():
configure_world()
configure_lights()
configure_meshes()
def init(self, prev_container):
store_existing(prev_container)
set_settings()
configure_world()
configure_lights()
configure_meshes(self)
print("Config mesh catch omitted: REMEMBER TO SET IT BACK NAXELA")
# try:
# configure_meshes(self)
# except Exception as e:
# print("An error occured during mesh configuration. See error below:")
# print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
# if not bpy.context.scene.TLM_SceneProperties.tlm_verbose:
# print("Turn on verbose mode to get more detail.")
def configure_world():
pass
def configure_lights():
pass
def configure_meshes(self):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Configuring meshes: Start")
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Configuring meshes: Material restore")
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
cache.backup_material_restore(obj)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Configuring meshes: Material rename check")
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
cache.backup_material_rename(obj)
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 = 0
currentIterNum = 0
scene = bpy.context.scene
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Object: Setting UV, converting modifiers and prepare channels")
#OBJECT: Set UV, CONVERT AND PREPARE
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
hidden = False
#We check if the object is hidden
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
#We check if the object's collection is hidden
collections = obj.users_collection
for collection in collections:
if collection.hide_viewport:
hidden = True
if collection.hide_render:
hidden = True
try:
if collection.name in bpy.context.scene.view_layers[0].layer_collection.children:
if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport:
hidden = True
except:
print("Error: Could not find collection: " + collection.name)
#Additional check for zero poly meshes
mesh = obj.data
if (len(mesh.polygons)) < 1:
print("Found an object with zero polygons. Skipping object: " + obj.name)
obj.TLM_ObjectProperties.tlm_mesh_lightmap_use = False
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use and not hidden:
print("Preparing: UV initiation for object: " + obj.name)
if len(obj.data.vertex_colors) < 1:
obj.data.vertex_colors.new(name="TLM")
if scene.TLM_SceneProperties.tlm_reset_uv:
uv_layers = obj.data.uv_layers
uv_channel = "UVMap_Lightmap"
for uvlayer in uv_layers:
if uvlayer.name == uv_channel:
uv_layers.remove(uvlayer)
if scene.TLM_SceneProperties.tlm_apply_on_unwrap:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
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)
if scene.TLM_SceneProperties.tlm_apply_modifiers:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Applying modifiers to: " + obj.name)
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.convert(target='MESH')
for slot in obj.material_slots:
material = slot.material
skipIncompatibleMaterials(material)
obj.hide_select = False #Remember to toggle this back
for slot in obj.material_slots:
if "." + slot.name + '_Original' in bpy.data.materials:
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']
#ATLAS UV PROJECTING
print("PREPARE: ATLAS")
for atlasgroup in scene.TLM_AtlasList:
print("Adding UV Projection for Atlas group: " + atlasgroup.name)
atlas = atlasgroup.name
atlas_items = []
bpy.ops.object.select_all(action='DESELECT')
#Atlas: Set UV, CONVERT AND PREPARE
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_atlas_pointer == atlasgroup.name:
hidden = False
#We check if the object is hidden
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
#We check if the object's collection is hidden
collections = obj.users_collection
for collection in collections:
if collection.hide_viewport:
hidden = True
if collection.hide_render:
hidden = True
try:
if collection.name in bpy.context.scene.view_layers[0].layer_collection.children:
if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport:
hidden = True
except:
print("Error: Could not find collection: " + collection.name)
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA" and not hidden:
uv_layers = obj.data.uv_layers
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
uv_channel = obj.TLM_ObjectProperties.tlm_uv_channel
else:
uv_channel = "UVMap_Lightmap"
if not uv_channel in uv_layers:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("UV map created for object: " + obj.name)
uvmap = uv_layers.new(name=uv_channel)
uv_layers.active_index = len(uv_layers) - 1
else:
print("Existing UV map found for object: " + obj.name)
for i in range(0, len(uv_layers)):
if uv_layers[i].name == 'UVMap_Lightmap':
uv_layers.active_index = i
break
atlas_items.append(obj)
obj.select_set(True)
if atlasgroup.tlm_atlas_lightmap_unwrap_mode == "SmartProject":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Atlasgroup Smart Project for: " + str(atlas_items))
for obj in atlas_items:
print("Applying Smart Project to: ")
print(obj.name + ": Active UV: " + obj.data.uv_layers[obj.data.uv_layers.active_index].name)
if len(atlas_items) > 0:
bpy.context.view_layer.objects.active = atlas_items[0]
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
#API changes in 2.91 causes errors:
if (2, 91, 0) > bpy.app.version:
bpy.ops.uv.smart_project(angle_limit=45.0, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, user_area_weight=1.0, use_aspect=True, stretch_to_bounds=False)
else:
angle = math.radians(45.0)
bpy.ops.uv.smart_project(angle_limit=angle, island_margin=obj.TLM_ObjectProperties.tlm_mesh_unwrap_margin, area_weight=1.0, correct_aspect=True, scale_to_bounds=False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
print("Smart project done.")
elif atlasgroup.tlm_atlas_lightmap_unwrap_mode == "Lightmap":
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.uv.lightmap_pack('EXEC_SCREEN', PREF_CONTEXT='ALL_FACES', PREF_MARGIN_DIV=atlasgroup.tlm_atlas_unwrap_margin)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
elif atlasgroup.tlm_atlas_lightmap_unwrap_mode == "Xatlas":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Using Xatlas on Atlas Group: " + atlas)
for obj in atlas_items:
obj.select_set(True)
if len(atlas_items) > 0:
bpy.context.view_layer.objects.active = atlas_items[0]
bpy.ops.object.mode_set(mode='EDIT')
Unwrap_Lightmap_Group_Xatlas_2_headless_call(obj)
bpy.ops.object.mode_set(mode='OBJECT')
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Copied Existing UV Map for Atlas Group: " + atlas)
if atlasgroup.tlm_use_uv_packer:
bpy.ops.object.select_all(action='DESELECT')
for obj in atlas_items:
obj.select_set(True)
if len(atlas_items) > 0:
bpy.context.view_layer.objects.active = atlas_items[0]
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.context.scene.UVPackerProps.uvp_padding = atlasgroup.tlm_uv_packer_padding
bpy.context.scene.UVPackerProps.uvp_engine = atlasgroup.tlm_uv_packer_packing_engine
#print(x)
print("!!!!!!!!!!!!!!!!!!!!! Using UV Packer on: " + obj.name)
if uv_layers.active == "UVMap_Lightmap":
print("YES")
else:
print("NO")
uv_layers.active_index = len(uv_layers) - 1
if uv_layers.active == "UVMap_Lightmap":
print("YES")
else:
print("NO")
uv_layers.active_index = len(uv_layers) - 1
bpy.ops.uvpackeroperator.packbtn()
# if bpy.context.scene.UVPackerProps.uvp_engine == "OP0":
# time.sleep(1)
# else:
# time.sleep(2)
time.sleep(2)
#FIX THIS! MAKE A SEPARATE CALL. THIS IS A THREADED ASYNC
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
#print(x)
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
iterNum = iterNum + 1
#OBJECT UV PROJECTING
print("PREPARE: OBJECTS")
for obj in bpy.context.scene.objects:
if obj.name in bpy.context.view_layer.objects: #Possible fix for view layer error
if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
hidden = False
#We check if the object is hidden
if obj.hide_get():
hidden = True
if obj.hide_viewport:
hidden = True
if obj.hide_render:
hidden = True
#We check if the object's collection is hidden
collections = obj.users_collection
for collection in collections:
if collection.hide_viewport:
hidden = True
if collection.hide_render:
hidden = True
try:
if collection.name in bpy.context.scene.view_layers[0].layer_collection.children:
if bpy.context.scene.view_layers[0].layer_collection.children[collection.name].hide_viewport:
hidden = True
except:
print("Error: Could not find collection: " + collection.name)
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use and not hidden:
objWasHidden = False
#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
#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
#Provide material if none exists
print("Preprocessing material for: " + obj.name)
preprocess_material(obj, scene)
#UV Layer management here
if not obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA":
print("Managing layer for Obj: " + obj.name)
uv_layers = obj.data.uv_layers
if not obj.TLM_ObjectProperties.tlm_use_default_channel:
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
#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)
if obj.TLM_ObjectProperties.tlm_use_uv_packer:
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.context.scene.UVPackerProps.uvp_padding = obj.TLM_ObjectProperties.tlm_uv_packer_padding
bpy.context.scene.UVPackerProps.uvp_engine = obj.TLM_ObjectProperties.tlm_uv_packer_packing_engine
#print(x)
print("!!!!!!!!!!!!!!!!!!!!! Using UV Packer on: " + obj.name)
if uv_layers.active == "UVMap_Lightmap":
print("YES")
else:
print("NO")
uv_layers.active_index = len(uv_layers) - 1
if uv_layers.active == "UVMap_Lightmap":
print("YES")
else:
print("NO")
uv_layers.active_index = len(uv_layers) - 1
bpy.ops.uvpackeroperator.packbtn()
if bpy.context.scene.UVPackerProps.uvp_engine == "OP0":
time.sleep(1)
else:
time.sleep(2)
#FIX THIS! MAKE A SEPARATE CALL. THIS IS A THREADED ASYNC
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
#print(x)
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Existing UV map found for obj: " + obj.name)
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 != "Leenkx PBR":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("The material group is not supported!")
if (mainNode.type == "ShaderNodeMixRGB"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Mix shader found")
#Skip for now
slot.material.TLM_ignore = True
if (mainNode.type == "BSDF_PRINCIPLED"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("BSDF_Principled")
if scene.TLM_EngineProperties.tlm_directional_mode == "None":
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Directional mode")
if not len(mainNode.inputs[22].links) == 0:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("NOT LEN 0")
ninput = mainNode.inputs[22].links[0]
noutput = mainNode.inputs[22].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.get("Metallic")
if not len(MainMetNodeSocket.links) == 0:
print("Creating new clamp node")
nodes = nodetree.nodes
MetClampNode = nodes.new('ShaderNodeClamp')
MetClampNode.location = (-200,150)
MetClampNode.inputs[2].default_value = 0.9
minput = mainNode.inputs.get("Metallic").links[0] #Metal input socket
moutput = mainNode.inputs.get("Metallic").links[0].from_socket #Output socket
nodetree.links.remove(minput)
nodetree.links.new(moutput, MetClampNode.inputs[0]) #minput node to clamp node
nodetree.links.new(MetClampNode.outputs[0], MainMetNodeSocket) #clamp node to metinput
elif mainNode.type == "PRINCIPLED_BSDF" and MainMetNodeSocket.links[0].from_node.type == "CLAMP":
pass
else:
print("New clamp node NOT made")
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_socket #Output socket
nodetree.links.remove(minput)
nodetree.links.new(moutput, MetClampNode.inputs[0]) #minput node to clamp node
nodetree.links.new(MetClampNode.outputs[0], MainMetNodeSocket) #clamp node to metinput
else:
mainNode.inputs[4].default_value = 0.0
else: #Skip
pass
if (mainNode.type == "BSDF_DIFFUSE"):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("BSDF_Diffuse")
# 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":
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)
def preprocess_material(obj, scene):
if len(obj.material_slots) == 0:
single = False
number = 0
while single == False:
matname = obj.name + ".00" + str(number)
if matname in bpy.data.materials:
single = False
number = number + 1
else:
mat = bpy.data.materials.new(name=matname)
mat.use_nodes = True
obj.data.materials.append(mat)
single = True
#We copy the existing material slots to an ordered array, which corresponds to the slot index
matArray = []
for slot in obj.material_slots:
matArray.append(slot.name)
obj["TLM_PrevMatArray"] = matArray
#We check and safeguard against NoneType
for slot in obj.material_slots:
if slot.material is None:
matName = obj.name + ".00" + str(0)
bpy.data.materials.new(name=matName)
slot.material = bpy.data.materials[matName]
slot.material.use_nodes = True
for slot in obj.material_slots:
cache.backup_material_copy(slot)
mat = slot.material
if mat.users > 1:
copymat = mat.copy()
slot.material = copymat
#SOME ATLAS EXCLUSION HERE?
ob = obj
for slot in ob.material_slots:
#If temporary material already exists
if slot.material.name.endswith('_temp'):
continue
n = slot.material.name + '_' + ob.name + '_temp'
if not n in bpy.data.materials:
slot.material = slot.material.copy()
slot.material.name = n
#Add images for baking
img_name = obj.name + '_baked'
#Resolution is object lightmap resolution divided by global scaler
if scene.TLM_EngineProperties.tlm_setting_supersample == "2x":
supersampling_scale = 2
elif scene.TLM_EngineProperties.tlm_setting_supersample == "4x":
supersampling_scale = 4
else:
supersampling_scale = 1
if (obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroupA" and obj.TLM_ObjectProperties.tlm_atlas_pointer != ""):
atlas_image_name = obj.TLM_ObjectProperties.tlm_atlas_pointer + "_baked"
res = int(scene.TLM_AtlasList[obj.TLM_ObjectProperties.tlm_atlas_pointer].tlm_atlas_lightmap_resolution) / int(scene.TLM_EngineProperties.tlm_resolution_scale) * int(supersampling_scale)
#If image not in bpy.data.images or if size changed, make a new image
if atlas_image_name not in bpy.data.images or bpy.data.images[atlas_image_name].size[0] != res or bpy.data.images[atlas_image_name].size[1] != res:
img = bpy.data.images.new(img_name, int(res), int(res), alpha=True, float_buffer=True)
num_pixels = len(img.pixels)
result_pixel = list(img.pixels)
for i in range(0,num_pixels,4):
if scene.TLM_SceneProperties.tlm_override_bg_color:
result_pixel[i+0] = scene.TLM_SceneProperties.tlm_override_color[0]
result_pixel[i+1] = scene.TLM_SceneProperties.tlm_override_color[1]
result_pixel[i+2] = scene.TLM_SceneProperties.tlm_override_color[2]
else:
result_pixel[i+0] = 0.0
result_pixel[i+1] = 0.0
result_pixel[i+2] = 0.0
result_pixel[i+3] = 1.0
img.pixels = result_pixel
img.name = atlas_image_name
else:
img = bpy.data.images[atlas_image_name]
for slot in obj.material_slots:
mat = slot.material
mat.use_nodes = True
nodes = mat.node_tree.nodes
if "Baked Image" in nodes:
img_node = nodes["Baked Image"]
else:
img_node = nodes.new('ShaderNodeTexImage')
img_node.name = 'Baked Image'
img_node.location = (100, 100)
img_node.image = img
img_node.select = True
nodes.active = img_node
#We need to save this file first in Blender 3.3 due to new filmic option?
image = img
saveDir = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
bakemap_path = os.path.join(saveDir, image.name)
filepath_ext = ".hdr"
image.filepath_raw = bakemap_path + filepath_ext
image.file_format = "HDR"
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Saving to: " + image.filepath_raw)
image.save()
else:
res = int(obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution) / int(scene.TLM_EngineProperties.tlm_resolution_scale) * int(supersampling_scale)
#If image not in bpy.data.images or if size changed, make a new image
if img_name not in bpy.data.images or bpy.data.images[img_name].size[0] != res or bpy.data.images[img_name].size[1] != res:
img = bpy.data.images.new(img_name, int(res), int(res), alpha=True, float_buffer=True)
num_pixels = len(img.pixels)
result_pixel = list(img.pixels)
for i in range(0,num_pixels,4):
if scene.TLM_SceneProperties.tlm_override_bg_color:
result_pixel[i+0] = scene.TLM_SceneProperties.tlm_override_color[0]
result_pixel[i+1] = scene.TLM_SceneProperties.tlm_override_color[1]
result_pixel[i+2] = scene.TLM_SceneProperties.tlm_override_color[2]
else:
result_pixel[i+0] = 0.0
result_pixel[i+1] = 0.0
result_pixel[i+2] = 0.0
result_pixel[i+3] = 1.0
img.pixels = result_pixel
img.name = img_name
else:
img = bpy.data.images[img_name]
for slot in obj.material_slots:
mat = slot.material
mat.use_nodes = True
nodes = mat.node_tree.nodes
if "Baked Image" in nodes:
img_node = nodes["Baked Image"]
else:
img_node = nodes.new('ShaderNodeTexImage')
img_node.name = 'Baked Image'
img_node.location = (100, 100)
img_node.image = img
img_node.select = True
nodes.active = img_node
#We need to save this file first in Blender 3.3 due to new filmic option?
image = img
saveDir = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
bakemap_path = os.path.join(saveDir, image.name)
filepath_ext = ".hdr"
image.filepath_raw = bakemap_path + filepath_ext
image.file_format = "HDR"
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Saving to: " + image.filepath_raw)
image.save()
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
print(bpy.app.version)
if bpy.app.version[0] == 3:
if cycles.device == "GPU":
scene.cycles.tile_size = 256
else:
scene.cycles.tile_size = 32
else:
if cycles.device == "GPU":
scene.render.tile_x = 256
scene.render.tile_y = 256
else:
scene.render.tile_x = 32
scene.render.tile_y = 32
if engineProperties.tlm_quality == "0":
cycles.samples = 32
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]
]
def skipIncompatibleMaterials(material):
node_tree = material.node_tree
nodes = material.node_tree.nodes
#ADD OR MIX SHADER? CUSTOM/GROUP?
#IF Principled has emissive or transparency?
SkipMatList = ["EMISSION",
"BSDF_TRANSPARENT",
"BACKGROUND",
"BSDF_HAIR",
"BSDF_HAIR_PRINCIPLED",
"HOLDOUT",
"PRINCIPLED_VOLUME",
"BSDF_REFRACTION",
"EEVEE_SPECULAR",
"BSDF_TRANSLUCENT",
"VOLUME_ABSORPTION",
"VOLUME_SCATTER"]
#Find output node
outputNode = nodes[0]
if(outputNode.type != "OUTPUT_MATERIAL"):
for node in node_tree.nodes:
if node.type == "OUTPUT_MATERIAL":
outputNode = node
break
#Find mainnode
mainNode = outputNode.inputs[0].links[0].from_node
if mainNode.type in SkipMatList:
material.TLM_ignore = True
print("Ignored material: " + material.name)
def packUVPack():
pass

View File

@ -0,0 +1,80 @@
import bpy, os
class TLM_Integrated_Denoise:
image_array = []
image_output_destination = ""
def load(self, images):
self.image_array = images
self.cull_undefined()
def setOutputDir(self, dir):
self.image_output_destination = dir
def cull_undefined(self):
#Do a validation check before denoising
cam = bpy.context.scene.camera
if not cam:
bpy.ops.object.camera_add()
#Just select the first camera we find, needed for the compositor
for obj in bpy.context.scene.objects:
if obj.type == "CAMERA":
bpy.context.scene.camera = obj
return
def denoise(self):
if not bpy.context.scene.use_nodes:
bpy.context.scene.use_nodes = True
tree = bpy.context.scene.node_tree
for image in self.image_array:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Image...: " + image)
img = bpy.data.images.load(self.image_output_destination + "/" + image)
image_node = tree.nodes.new(type='CompositorNodeImage')
image_node.image = img
image_node.location = 0, 0
denoise_node = tree.nodes.new(type='CompositorNodeDenoise')
denoise_node.location = 300, 0
comp_node = tree.nodes.new('CompositorNodeComposite')
comp_node.location = 600, 0
links = tree.links
links.new(image_node.outputs[0], denoise_node.inputs[0])
links.new(denoise_node.outputs[0], comp_node.inputs[0])
# set output resolution to image res
bpy.context.scene.render.resolution_x = img.size[0]
bpy.context.scene.render.resolution_y = img.size[1]
bpy.context.scene.render.resolution_percentage = 100
filePath = bpy.data.filepath
path = os.path.dirname(filePath)
base = os.path.basename(image)
filename, file_extension = os.path.splitext(image)
filename = filename[:-6]
bpy.context.scene.render.filepath = self.image_output_destination + "/" + filename + "_denoised" + file_extension
denoised_image_path = self.image_output_destination
bpy.context.scene.render.image_settings.file_format = "HDR"
bpy.ops.render.render(write_still=True)
#Cleanup
comp_nodes = [image_node, denoise_node, comp_node]
for node in comp_nodes:
tree.nodes.remove(node)

View File

@ -0,0 +1,207 @@
import bpy, os, sys, re, platform, subprocess
import numpy as np
class TLM_OIDN_Denoise:
image_array = []
image_output_destination = ""
denoised_array = []
def __init__(self, oidnProperties, img_array, dirpath):
self.oidnProperties = oidnProperties
self.image_array = img_array
self.image_output_destination = dirpath
self.check_binary()
def check_binary(self):
oidnPath = self.oidnProperties.tlm_oidn_path
if oidnPath != "":
file = oidnPath
filename, file_extension = os.path.splitext(file)
if platform.system() == 'Windows':
if(file_extension == ".exe"):
pass
else:
self.oidnProperties.tlm_oidn_path = os.path.join(self.oidnProperties.tlm_oidn_path,"oidnDenoise.exe")
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Please provide OIDN path")
def denoise(self):
for image in self.image_array:
if image not in self.denoised_array:
image_path = os.path.join(self.image_output_destination, image)
#Save to pfm
loaded_image = bpy.data.images.load(image_path, check_existing=False)
width = loaded_image.size[0]
height = loaded_image.size[1]
image_output_array = np.zeros([width, height, 3], dtype="float32")
image_output_array = np.array(loaded_image.pixels)
image_output_array = image_output_array.reshape(height, width, 4)
image_output_array = np.float32(image_output_array[:,:,:3])
image_output_denoise_destination = image_path[:-4] + ".pfm"
image_output_denoise_result_destination = image_path[:-4] + "_denoised.pfm"
with open(image_output_denoise_destination, "wb") as fileWritePFM:
self.save_pfm(fileWritePFM, image_output_array)
#Denoise
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Loaded image: " + str(loaded_image))
verbose = self.oidnProperties.tlm_oidn_verbose
affinity = self.oidnProperties.tlm_oidn_affinity
if verbose:
print("Denoiser search: " + bpy.path.abspath(self.oidnProperties.tlm_oidn_path))
v = "3"
else:
v = "0"
if affinity:
a = "1"
else:
a = "0"
threads = str(self.oidnProperties.tlm_oidn_threads)
maxmem = str(self.oidnProperties.tlm_oidn_maxmem)
if platform.system() == 'Windows':
oidnPath = bpy.path.abspath(self.oidnProperties.tlm_oidn_path)
pipePath = [oidnPath, '-f', 'RTLightmap', '-hdr', image_output_denoise_destination, '-o', image_output_denoise_result_destination, '-verbose', v, '-threads', threads, '-affinity', a, '-maxmem', maxmem]
elif platform.system() == 'Darwin':
oidnPath = bpy.path.abspath(self.oidnProperties.tlm_oidn_path)
pipePath = [oidnPath + ' -f ' + ' RTLightmap ' + ' -hdr ' + image_output_denoise_destination + ' -o ' + image_output_denoise_result_destination + ' -verbose ' + v]
else:
oidnPath = bpy.path.abspath(self.oidnProperties.tlm_oidn_path)
oidnPath = oidnPath.replace(' ', '\\ ')
image_output_denoise_destination = image_output_denoise_destination.replace(' ', '\\ ')
image_output_denoise_result_destination = image_output_denoise_result_destination.replace(' ', '\\ ')
pipePath = [oidnPath + ' -f ' + ' RTLightmap ' + ' -hdr ' + image_output_denoise_destination + ' -o ' + image_output_denoise_result_destination + ' -verbose ' + v]
if not verbose:
denoisePipe = subprocess.Popen(pipePath, stdout=subprocess.PIPE, stderr=None, shell=True)
else:
denoisePipe = subprocess.Popen(pipePath, shell=True)
denoisePipe.communicate()[0]
if platform.system() != 'Windows':
image_output_denoise_result_destination = image_output_denoise_result_destination.replace('\\', '')
with open(image_output_denoise_result_destination, "rb") as f:
denoise_data, scale = self.load_pfm(f)
ndata = np.array(denoise_data)
ndata2 = np.dstack((ndata, np.ones((width,height))))
img_array = ndata2.ravel()
loaded_image.pixels = img_array
loaded_image.filepath_raw = image_output_denoise_result_destination = image_path[:-10] + "_denoised.hdr"
loaded_image.file_format = "HDR"
loaded_image.save()
self.denoised_array.append(image)
print(image_path)
def clean(self):
self.denoised_array.clear()
self.image_array.clear()
for file in self.image_output_destination:
if file.endswith("_baked.hdr"):
baked_image_array.append(file)
#self.image_output_destination
#Clean temporary files here..
#...pfm
#...denoised.hdr
def load_pfm(self, file, as_flat_list=False):
#start = time()
header = file.readline().decode("utf-8").rstrip()
if header == "PF":
color = True
elif header == "Pf":
color = False
else:
raise Exception("Not a PFM file.")
dim_match = re.match(r"^(\d+)\s(\d+)\s$", file.readline().decode("utf-8"))
if dim_match:
width, height = map(int, dim_match.groups())
else:
raise Exception("Malformed PFM header.")
scale = float(file.readline().decode("utf-8").rstrip())
if scale < 0: # little-endian
endian = "<"
scale = -scale
else:
endian = ">" # big-endian
data = np.fromfile(file, endian + "f")
shape = (height, width, 3) if color else (height, width)
if as_flat_list:
result = data
else:
result = np.reshape(data, shape)
#print("PFM import took %.3f s" % (time() - start))
return result, scale
def save_pfm(self, file, image, scale=1):
#start = time()
if image.dtype.name != "float32":
raise Exception("Image dtype must be float32 (got %s)" % image.dtype.name)
if len(image.shape) == 3 and image.shape[2] == 3: # color image
color = True
elif len(image.shape) == 2 or len(image.shape) == 3 and image.shape[2] == 1: # greyscale
color = False
else:
raise Exception("Image must have H x W x 3, H x W x 1 or H x W dimensions.")
file.write(b"PF\n" if color else b"Pf\n")
file.write(b"%d %d\n" % (image.shape[1], image.shape[0]))
endian = image.dtype.byteorder
if endian == "<" or endian == "=" and sys.byteorder == "little":
scale = -scale
file.write(b"%f\n" % scale)
image.tofile(file)
#print("PFM export took %.3f s" % (time() - start))

View File

@ -0,0 +1,92 @@
import bpy, os, platform, subprocess
class TLM_Optix_Denoise:
image_array = []
image_output_destination = ""
denoised_array = []
def __init__(self, optixProperties, img_array, dirpath):
self.optixProperties = optixProperties
self.image_array = img_array
self.image_output_destination = dirpath
self.check_binary()
def check_binary(self):
optixPath = self.optixProperties.tlm_optix_path
if optixPath != "":
file = optixPath
filename, file_extension = os.path.splitext(file)
if(file_extension == ".exe"):
#if file exists optixDenoise or denoise
pass
else:
#if file exists optixDenoise or denoise
self.optixProperties.tlm_optix_path = os.path.join(self.optixProperties.tlm_optix_path,"Denoiser.exe")
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Please provide Optix path")
def denoise(self):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Optix: Denoising")
for image in self.image_array:
if image not in self.denoised_array:
image_path = os.path.join(self.image_output_destination, image)
denoise_output_destination = image_path[:-10] + "_denoised.hdr"
if platform.system() == 'Windows':
optixPath = bpy.path.abspath(self.optixProperties.tlm_optix_path)
pipePath = [optixPath, '-i', image_path, '-o', denoise_output_destination]
elif platform.system() == 'Darwin':
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Mac for Optix is still unsupported")
else:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Linux for Optix is still unsupported")
if self.optixProperties.tlm_optix_verbose:
denoisePipe = subprocess.Popen(pipePath, shell=True)
else:
denoisePipe = subprocess.Popen(pipePath, stdout=subprocess.PIPE, stderr=None, shell=True)
denoisePipe.communicate()[0]
image = bpy.data.images.load(image_path, check_existing=False)
bpy.data.images[image.name].filepath_raw = bpy.data.images[image.name].filepath_raw[:-4] + "_denoised.hdr"
bpy.data.images[image.name].reload()
def clean(self):
self.denoised_array.clear()
self.image_array.clear()
for file in self.image_output_destination:
if file.endswith("_baked.hdr"):
baked_image_array.append(file)
#self.image_output_destination
#Clean temporary files here..
#...pfm
#...denoised.hdr

View File

@ -0,0 +1,674 @@
import bpy, math, os, gpu, bgl, importlib
import numpy as np
from . import utility
from fractions import Fraction
from gpu_extras.batch import batch_for_shader
def splitLogLuvAlphaAtlas(imageIn, outDir, quality):
pass
def splitLogLuvAlpha(imageIn, outDir, quality):
bpy.app.driver_namespace["logman"].append("Starting LogLuv split for: " + str(imageIn))
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
print("CV2 not found - Ignoring filtering")
return 0
else:
cv2 = importlib.__import__("cv2")
print(imageIn)
image = cv2.imread(imageIn, cv2.IMREAD_UNCHANGED)
#cv2.imshow('image', image)
split = cv2.split(image)
merged = cv2.merge([split[0], split[1], split[2]])
alpha = split[3]
#b,g,r = cv2.split(image)
#merged = cv2.merge([b, g, r])
#alpha = cv2.merge([a,a,a])
image_name = os.path.basename(imageIn)[:-4]
#os.path.join(outDir, image_name+"_XYZ.png")
cv2.imwrite(os.path.join(outDir, image_name+"_XYZ.png"), merged)
cv2.imwrite(os.path.join(outDir, image_name+"_W.png"), alpha)
def encodeLogLuvGPU(image, outDir, quality):
bpy.app.driver_namespace["logman"].append("Starting LogLuv encode for: " + str(image.name))
input_image = bpy.data.images[image.name]
image_name = input_image.name
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;
const mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );
vec4 LinearToLogLuv( in vec4 value ) {
vec3 Xp_Y_XYZp = cLogLuvM * value.rgb;
Xp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );
vec4 vResult;
vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;
float Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;
vResult.w = fract( Le );
vResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;
return vResult;
//return vec4(Xp_Y_XYZp,1);
}
const mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );
vec4 LogLuvToLinear( in vec4 value ) {
float Le = value.z * 255.0 + value.w;
vec3 Xp_Y_XYZp;
Xp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );
Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;
Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;
vec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;
//return vec4( max( vRGB, 0.0 ), 1.0 );
return vec4( max( Xp_Y_XYZp, 0.0 ), 1.0 );
}
void main()
{
//fragColor = LinearToLogLuv(pow(texture(image, texCoord_interp), vec4(0.454)));
fragColor = LinearToLogLuv(texture(image, texCoord_interp));
//fragColor = LogLuvToLinear(LinearToLogLuv(texture(image, texCoord_interp)));
}
'''
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()
def encodeImageRGBDGPU(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 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);
}
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 = toRGBD(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()
#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
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
)
num_pixels = len(input_image.pixels)
result_pixel = list(input_image.pixels)
for i in range(0,num_pixels,4):
for j in range(3):
result_pixel[i+j] *= 1.0 / maxRange;
result_pixel[i+3] = saturate(max(result_pixel[i], result_pixel[i+1], result_pixel[i+2], 1e-6))
result_pixel[i+3] = math.ceil(result_pixel[i+3] * 255.0) / 255.0
for j in range(3):
result_pixel[i+j] /= result_pixel[i+3]
target_image.pixels = result_pixel
input_image = target_image
#Save RGBM
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(input_image.name)
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()
#input_image.save_render(filepath = input_image.filepath_raw, scene = bpy.context.scene)
# 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.
#input_image.save()
def saturate(num, floats=True):
if num <= 0:
num = 0
elif num > (1 if floats else 255):
num = (1 if floats else 255)
return num
def maxEps(x):
return max(x, 1e-6)
def encodeImageRGBDCPU(image, maxRange, outDir, quality):
input_image = bpy.data.images[image.name]
image_name = input_image.name
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 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
)
num_pixels = len(input_image.pixels)
result_pixel = list(input_image.pixels)
rgbdMaxRange = 255.0
for i in range(0,num_pixels,4):
maxRGB = maxEps(max(result_pixel[i], result_pixel[i+1], result_pixel[i+2]))
D = max(rgbdMaxRange/maxRGB, 1.0)
D = np.clip((math.floor(D) / 255.0), 0.0, 1.0)
result_pixel[i] = math.pow(result_pixel[i] * D, 1/2.2)
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
target_image.pixels = result_pixel
input_image = target_image
#Save RGBD
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print(input_image.name)
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()

View File

@ -0,0 +1,49 @@
import bpy, os, importlib
from os import listdir
from os.path import isfile, join
class TLM_NP_Filtering:
image_output_destination = ""
def init(lightmap_dir, denoise):
scene = bpy.context.scene
print("Beginning filtering for files: ")
if denoise:
file_ending = "_denoised.hdr"
else:
file_ending = "_baked.hdr"
dirfiles = [f for f in listdir(lightmap_dir) if isfile(join(lightmap_dir, f))]
for file in dirfiles:
if denoise:
file_ending = "_denoised.hdr"
file_split = 13
else:
file_ending = "_baked.hdr"
file_split = 10
if file.endswith(file_ending):
file_input = os.path.join(lightmap_dir, file)
os.chdir(lightmap_dir)
#opencv_process_image = cv2.imread(file_input, -1)
print("Filtering: " + file_input)
print(os.path.join(lightmap_dir, file))
if scene.TLM_SceneProperties.tlm_numpy_filtering_mode == "3x3 blur":
pass
#filter_file_output = os.path.join(lightmap_dir, file[:-file_split] + "_filtered.hdr")
#cv2.imwrite(filter_file_output, opencv_bl_result)
print("Written to: " + filter_file_output)

View File

@ -0,0 +1,178 @@
import bpy, os, importlib
from os import listdir
from os.path import isfile, join
class TLM_CV_Filtering:
image_output_destination = ""
def init(lightmap_dir, denoise):
scene = bpy.context.scene
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Beginning filtering for files: ")
if denoise:
file_ending = "_denoised.hdr"
else:
file_ending = "_baked.hdr"
dirfiles = [f for f in listdir(lightmap_dir) if isfile(join(lightmap_dir, f))]
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("CV2 not found - Ignoring filtering")
return 0
else:
cv2 = importlib.__import__("cv2")
for file in dirfiles:
if denoise:
file_ending = "_denoised.hdr"
file_split = 13
else:
file_ending = "_baked.hdr"
file_split = 10
if file.endswith(file_ending):
file_input = os.path.join(lightmap_dir, file)
os.chdir(lightmap_dir)
opencv_process_image = cv2.imread(file_input, -1)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Filtering: " + os.path.basename(file_input))
obj_name = os.path.basename(file_input).split("_")[0]
#SEAM TESTING# #####################
# obj = bpy.data.objects[obj_name]
# bpy.context.view_layer.objects.active = obj
# bpy.ops.object.mode_set(mode='EDIT')
# bpy.ops.uv.export_layout(filepath=os.path.join(lightmap_dir,obj_name), export_all=True, mode='PNG', opacity=0.0)
# bpy.ops.object.mode_set(mode='OBJECT')
# print("Exported")
#SEAM TESTING# #####################
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
else:
override = False
if override:
print(os.path.join(lightmap_dir, file))
objectProperties = bpy.data.objects[obj_name].TLM_ObjectProperties
#TODO OVERRIDE FILTERING OPTION! REWRITE
if objectProperties.tlm_mesh_filtering_mode == "Box":
if objectProperties.tlm_mesh_filtering_box_strength % 2 == 0:
kernel_size = (objectProperties.tlm_mesh_filtering_box_strength + 1, objectProperties.tlm_mesh_filtering_box_strength + 1)
else:
kernel_size = (objectProperties.tlm_mesh_filtering_box_strength, objectProperties.tlm_mesh_filtering_box_strength)
opencv_bl_result = cv2.blur(opencv_process_image, kernel_size)
if objectProperties.tlm_mesh_filtering_iterations > 1:
for x in range(objectProperties.tlm_mesh_filtering_iterations):
opencv_bl_result = cv2.blur(opencv_bl_result, kernel_size)
elif objectProperties.tlm_mesh_filtering_mode == "Gaussian":
if objectProperties.tlm_mesh_filtering_gaussian_strength % 2 == 0:
kernel_size = (objectProperties.tlm_mesh_filtering_gaussian_strength + 1, objectProperties.tlm_mesh_filtering_gaussian_strength + 1)
else:
kernel_size = (objectProperties.tlm_mesh_filtering_gaussian_strength, objectProperties.tlm_mesh_filtering_gaussian_strength)
sigma_size = 0
opencv_bl_result = cv2.GaussianBlur(opencv_process_image, kernel_size, sigma_size)
if objectProperties.tlm_mesh_filtering_iterations > 1:
for x in range(objectProperties.tlm_mesh_filtering_iterations):
opencv_bl_result = cv2.GaussianBlur(opencv_bl_result, kernel_size, sigma_size)
elif objectProperties.tlm_mesh_filtering_mode == "Bilateral":
diameter_size = objectProperties.tlm_mesh_filtering_bilateral_diameter
sigma_color = objectProperties.tlm_mesh_filtering_bilateral_color_deviation
sigma_space = objectProperties.tlm_mesh_filtering_bilateral_coordinate_deviation
opencv_bl_result = cv2.bilateralFilter(opencv_process_image, diameter_size, sigma_color, sigma_space)
if objectProperties.tlm_mesh_filtering_iterations > 1:
for x in range(objectProperties.tlm_mesh_filtering_iterations):
opencv_bl_result = cv2.bilateralFilter(opencv_bl_result, diameter_size, sigma_color, sigma_space)
else:
if objectProperties.tlm_mesh_filtering_median_kernel % 2 == 0:
kernel_size = (objectProperties.tlm_mesh_filtering_median_kernel + 1, objectProperties.tlm_mesh_filtering_median_kernel + 1)
else:
kernel_size = (objectProperties.tlm_mesh_filtering_median_kernel, objectProperties.tlm_mesh_filtering_median_kernel)
opencv_bl_result = cv2.medianBlur(opencv_process_image, kernel_size[0])
if objectProperties.tlm_mesh_filtering_iterations > 1:
for x in range(objectProperties.tlm_mesh_filtering_iterations):
opencv_bl_result = cv2.medianBlur(opencv_bl_result, kernel_size[0])
filter_file_output = os.path.join(lightmap_dir, file[:-file_split] + "_filtered.hdr")
cv2.imwrite(filter_file_output, opencv_bl_result)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Written to: " + filter_file_output)
else:
print(os.path.join(lightmap_dir, file))
#TODO OVERRIDE FILTERING OPTION!
if scene.TLM_SceneProperties.tlm_filtering_mode == "Box":
if scene.TLM_SceneProperties.tlm_filtering_box_strength % 2 == 0:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_box_strength + 1,scene.TLM_SceneProperties.tlm_filtering_box_strength + 1)
else:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_box_strength,scene.TLM_SceneProperties.tlm_filtering_box_strength)
opencv_bl_result = cv2.blur(opencv_process_image, kernel_size)
if scene.TLM_SceneProperties.tlm_filtering_iterations > 1:
for x in range(scene.TLM_SceneProperties.tlm_filtering_iterations):
opencv_bl_result = cv2.blur(opencv_bl_result, kernel_size)
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Gaussian":
if scene.TLM_SceneProperties.tlm_filtering_gaussian_strength % 2 == 0:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_gaussian_strength + 1,scene.TLM_SceneProperties.tlm_filtering_gaussian_strength + 1)
else:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_gaussian_strength,scene.TLM_SceneProperties.tlm_filtering_gaussian_strength)
sigma_size = 0
opencv_bl_result = cv2.GaussianBlur(opencv_process_image, kernel_size, sigma_size)
if scene.TLM_SceneProperties.tlm_filtering_iterations > 1:
for x in range(scene.TLM_SceneProperties.tlm_filtering_iterations):
opencv_bl_result = cv2.GaussianBlur(opencv_bl_result, kernel_size, sigma_size)
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Bilateral":
diameter_size = scene.TLM_SceneProperties.tlm_filtering_bilateral_diameter
sigma_color = scene.TLM_SceneProperties.tlm_filtering_bilateral_color_deviation
sigma_space = scene.TLM_SceneProperties.tlm_filtering_bilateral_coordinate_deviation
opencv_bl_result = cv2.bilateralFilter(opencv_process_image, diameter_size, sigma_color, sigma_space)
if scene.TLM_SceneProperties.tlm_filtering_iterations > 1:
for x in range(scene.TLM_SceneProperties.tlm_filtering_iterations):
opencv_bl_result = cv2.bilateralFilter(opencv_bl_result, diameter_size, sigma_color, sigma_space)
else:
if scene.TLM_SceneProperties.tlm_filtering_median_kernel % 2 == 0:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_median_kernel + 1 , scene.TLM_SceneProperties.tlm_filtering_median_kernel + 1)
else:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_median_kernel, scene.TLM_SceneProperties.tlm_filtering_median_kernel)
opencv_bl_result = cv2.medianBlur(opencv_process_image, kernel_size[0])
if scene.TLM_SceneProperties.tlm_filtering_iterations > 1:
for x in range(scene.TLM_SceneProperties.tlm_filtering_iterations):
opencv_bl_result = cv2.medianBlur(opencv_bl_result, kernel_size[0])
filter_file_output = os.path.join(lightmap_dir, file[:-file_split] + "_filtered.hdr")
cv2.imwrite(filter_file_output, opencv_bl_result)
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Written to: " + filter_file_output)

View File

@ -0,0 +1,160 @@
import bpy, os, importlib
from os import listdir
from os.path import isfile, join
class TLM_Shader_Filtering:
image_output_destination = ""
def init(lightmap_dir, denoise):
scene = bpy.context.scene
print("Beginning filtering for files: ")
if denoise:
file_ending = "_denoised.hdr"
else:
file_ending = "_baked.hdr"
dirfiles = [f for f in listdir(lightmap_dir) if isfile(join(lightmap_dir, f))]
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
print("CV2 not found - Ignoring filtering")
return 0
else:
cv2 = importlib.__import__("cv2")
for file in dirfiles:
if denoise:
file_ending = "_denoised.hdr"
file_split = 13
else:
file_ending = "_baked.hdr"
file_split = 10
if file.endswith(file_ending):
file_input = os.path.join(lightmap_dir, file)
os.chdir(lightmap_dir)
opencv_process_image = cv2.imread(file_input, -1)
print("Filtering: " + os.path.basename(file_input))
obj_name = os.path.basename(file_input).split("_")[0]
if bpy.data.objects[obj_name].TLM_ObjectProperties.tlm_mesh_filter_override:
print("OVERRIDE!")
print(os.path.join(lightmap_dir, file))
objectProperties = bpy.data.objects[obj_name].TLM_ObjectProperties
#TODO OVERRIDE FILTERING OPTION! REWRITE
if objectProperties.tlm_mesh_filtering_mode == "Box":
if objectProperties.tlm_mesh_filtering_box_strength % 2 == 0:
kernel_size = (objectProperties.tlm_mesh_filtering_box_strength + 1, objectProperties.tlm_mesh_filtering_box_strength + 1)
else:
kernel_size = (objectProperties.tlm_mesh_filtering_box_strength, objectProperties.tlm_mesh_filtering_box_strength)
opencv_bl_result = cv2.blur(opencv_process_image, kernel_size)
if objectProperties.tlm_mesh_filtering_iterations > 1:
for x in range(objectProperties.tlm_mesh_filtering_iterations):
opencv_bl_result = cv2.blur(opencv_bl_result, kernel_size)
elif objectProperties.tlm_mesh_filtering_mode == "Gaussian":
if objectProperties.tlm_mesh_filtering_gaussian_strength % 2 == 0:
kernel_size = (objectProperties.tlm_mesh_filtering_gaussian_strength + 1, objectProperties.tlm_mesh_filtering_gaussian_strength + 1)
else:
kernel_size = (objectProperties.tlm_mesh_filtering_gaussian_strength, objectProperties.tlm_mesh_filtering_gaussian_strength)
sigma_size = 0
opencv_bl_result = cv2.GaussianBlur(opencv_process_image, kernel_size, sigma_size)
if objectProperties.tlm_mesh_filtering_iterations > 1:
for x in range(objectProperties.tlm_mesh_filtering_iterations):
opencv_bl_result = cv2.GaussianBlur(opencv_bl_result, kernel_size, sigma_size)
elif objectProperties.tlm_mesh_filtering_mode == "Bilateral":
diameter_size = objectProperties.tlm_mesh_filtering_bilateral_diameter
sigma_color = objectProperties.tlm_mesh_filtering_bilateral_color_deviation
sigma_space = objectProperties.tlm_mesh_filtering_bilateral_coordinate_deviation
opencv_bl_result = cv2.bilateralFilter(opencv_process_image, diameter_size, sigma_color, sigma_space)
if objectProperties.tlm_mesh_filtering_iterations > 1:
for x in range(objectProperties.tlm_mesh_filtering_iterations):
opencv_bl_result = cv2.bilateralFilter(opencv_bl_result, diameter_size, sigma_color, sigma_space)
else:
if objectProperties.tlm_mesh_filtering_median_kernel % 2 == 0:
kernel_size = (objectProperties.tlm_mesh_filtering_median_kernel + 1, objectProperties.tlm_mesh_filtering_median_kernel + 1)
else:
kernel_size = (objectProperties.tlm_mesh_filtering_median_kernel, objectProperties.tlm_mesh_filtering_median_kernel)
opencv_bl_result = cv2.medianBlur(opencv_process_image, kernel_size[0])
if objectProperties.tlm_mesh_filtering_iterations > 1:
for x in range(objectProperties.tlm_mesh_filtering_iterations):
opencv_bl_result = cv2.medianBlur(opencv_bl_result, kernel_size[0])
filter_file_output = os.path.join(lightmap_dir, file[:-file_split] + "_filtered.hdr")
cv2.imwrite(filter_file_output, opencv_bl_result)
print("Written to: " + filter_file_output)
else:
print(os.path.join(lightmap_dir, file))
#TODO OVERRIDE FILTERING OPTION!
if scene.TLM_SceneProperties.tlm_filtering_mode == "Box":
if scene.TLM_SceneProperties.tlm_filtering_box_strength % 2 == 0:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_box_strength + 1,scene.TLM_SceneProperties.tlm_filtering_box_strength + 1)
else:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_box_strength,scene.TLM_SceneProperties.tlm_filtering_box_strength)
opencv_bl_result = cv2.blur(opencv_process_image, kernel_size)
if scene.TLM_SceneProperties.tlm_filtering_iterations > 1:
for x in range(scene.TLM_SceneProperties.tlm_filtering_iterations):
opencv_bl_result = cv2.blur(opencv_bl_result, kernel_size)
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Gaussian":
if scene.TLM_SceneProperties.tlm_filtering_gaussian_strength % 2 == 0:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_gaussian_strength + 1,scene.TLM_SceneProperties.tlm_filtering_gaussian_strength + 1)
else:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_gaussian_strength,scene.TLM_SceneProperties.tlm_filtering_gaussian_strength)
sigma_size = 0
opencv_bl_result = cv2.GaussianBlur(opencv_process_image, kernel_size, sigma_size)
if scene.TLM_SceneProperties.tlm_filtering_iterations > 1:
for x in range(scene.TLM_SceneProperties.tlm_filtering_iterations):
opencv_bl_result = cv2.GaussianBlur(opencv_bl_result, kernel_size, sigma_size)
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Bilateral":
diameter_size = scene.TLM_SceneProperties.tlm_filtering_bilateral_diameter
sigma_color = scene.TLM_SceneProperties.tlm_filtering_bilateral_color_deviation
sigma_space = scene.TLM_SceneProperties.tlm_filtering_bilateral_coordinate_deviation
opencv_bl_result = cv2.bilateralFilter(opencv_process_image, diameter_size, sigma_color, sigma_space)
if scene.TLM_SceneProperties.tlm_filtering_iterations > 1:
for x in range(scene.TLM_SceneProperties.tlm_filtering_iterations):
opencv_bl_result = cv2.bilateralFilter(opencv_bl_result, diameter_size, sigma_color, sigma_space)
else:
if scene.TLM_SceneProperties.tlm_filtering_median_kernel % 2 == 0:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_median_kernel + 1 , scene.TLM_SceneProperties.tlm_filtering_median_kernel + 1)
else:
kernel_size = (scene.TLM_SceneProperties.tlm_filtering_median_kernel, scene.TLM_SceneProperties.tlm_filtering_median_kernel)
opencv_bl_result = cv2.medianBlur(opencv_process_image, kernel_size[0])
if scene.TLM_SceneProperties.tlm_filtering_iterations > 1:
for x in range(scene.TLM_SceneProperties.tlm_filtering_iterations):
opencv_bl_result = cv2.medianBlur(opencv_bl_result, kernel_size[0])
filter_file_output = os.path.join(lightmap_dir, file[:-file_split] + "_filtered.hdr")
cv2.imwrite(filter_file_output, opencv_bl_result)
print("Written to: " + filter_file_output)
# if file.endswith(file_ending):
# print()
# baked_image_array.append(file)

View File

@ -0,0 +1,77 @@
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)
for img in bpy.data.images:
if img.filepath.endswith(image_name):
image = img
break
if not image:
image = bpy.data.images[image_name]
x = 15
y = 15
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)
try:
bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.image.bindcode)
except:
bpy.types.SpaceView3D.draw_handler_remove(self.handle2, 'WINDOW')
self.shader.bind()
self.shader.uniform_int("image", 0)
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,31 @@
import os
import bpy
from bpy.utils import previews
icons = None
directory = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'icons'))
def id(identifier):
return image(identifier).icon_id
def image(identifier):
def icon(identifier):
if identifier in icons:
return icons[identifier]
return icons.load(identifier, os.path.join(directory, identifier + '.png'), 'IMAGE')
if icons:
return icon(identifier)
else:
create()
return icon(identifier)
def create():
global icons
icons = previews.new()
def remove():
previews.remove(icons)

View File

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

View File

@ -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

@ -0,0 +1,354 @@
import bpy, os, sys, math, mathutils, importlib
import numpy as np
from . rectpack import newPacker, PackingMode, PackingBin
def postpack():
cv_installed = False
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
print("CV2 not found - Ignoring postpacking")
return 0
else:
cv2 = importlib.__import__("cv2")
cv_installed = True
if cv_installed:
lightmap_directory = os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.scene.TLM_EngineProperties.tlm_lightmap_savedir)
packedAtlas = {}
#TODO - TEST WITH ONLY 1 ATLAS AT FIRST (1 Atlas for each, but only 1 bin (no overflow))
#PackedAtlas = Packer
#Each atlas has bins
#Each bins has rects
#Each rect corresponds to a pack_object
scene = bpy.context.scene
sceneProperties = scene.TLM_SceneProperties
end = "_baked"
if sceneProperties.tlm_denoise_use:
end = "_denoised"
if sceneProperties.tlm_filtering_use:
end = "_filtered"
formatEnc = ".hdr"
image_channel_depth = cv2.IMREAD_ANYDEPTH
linear_straight = False
if sceneProperties.tlm_encoding_use and scene.TLM_EngineProperties.tlm_bake_mode != "Background":
if sceneProperties.tlm_encoding_device == "CPU":
if sceneProperties.tlm_encoding_mode_a == "HDR":
if sceneProperties.tlm_format == "EXR":
formatEnc = ".exr"
if sceneProperties.tlm_encoding_mode_a == "RGBM":
formatEnc = "_encoded.png"
image_channel_depth = cv2.IMREAD_UNCHANGED
else:
if sceneProperties.tlm_encoding_mode_b == "HDR":
if sceneProperties.tlm_format == "EXR":
formatEnc = ".exr"
if sceneProperties.tlm_encoding_mode_b == "LogLuv":
formatEnc = "_encoded.png"
image_channel_depth = cv2.IMREAD_UNCHANGED
linear_straight = True
if sceneProperties.tlm_encoding_mode_b == "RGBM":
formatEnc = "_encoded.png"
image_channel_depth = cv2.IMREAD_UNCHANGED
if sceneProperties.tlm_encoding_mode_b == "RGBD":
formatEnc = "_encoded.png"
image_channel_depth = cv2.IMREAD_UNCHANGED
packer = {}
for atlas in bpy.context.scene.TLM_PostAtlasList: #For each atlas
packer[atlas.name] = newPacker(PackingMode.Offline, PackingBin.BFF, rotation=False)
bpy.app.driver_namespace["logman"].append("Postpacking: " + str(atlas.name))
if scene.TLM_EngineProperties.tlm_setting_supersample == "2x":
supersampling_scale = 2
elif scene.TLM_EngineProperties.tlm_setting_supersample == "4x":
supersampling_scale = 4
else:
supersampling_scale = 1
atlas_resolution = int(int(atlas.tlm_atlas_lightmap_resolution) / int(scene.TLM_EngineProperties.tlm_resolution_scale) * int(supersampling_scale))
packer[atlas.name].add_bin(atlas_resolution, atlas_resolution, 1)
#AtlasList same name prevention?
rect = []
#For each object that targets the atlas
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:
res = int(int(obj.TLM_ObjectProperties.tlm_mesh_lightmap_resolution) / int(scene.TLM_EngineProperties.tlm_resolution_scale) * int(supersampling_scale))
rect.append((res, res, obj.name))
#Add rect to bin
for r in rect:
packer[atlas.name].add_rect(*r)
print("Rects: " + str(rect))
print("Bins:" + str(packer[atlas.name]))
packedAtlas[atlas.name] = np.zeros((atlas_resolution,atlas_resolution, 3), dtype="float32")
#Continue here...overwrite value if using 8-bit encoding
if sceneProperties.tlm_encoding_use:
if sceneProperties.tlm_encoding_device == "CPU":
if sceneProperties.tlm_encoding_mode_a == "RGBM":
packedAtlas[atlas.name] = np.zeros((atlas_resolution,atlas_resolution, 4), dtype=np.uint8)
if sceneProperties.tlm_encoding_mode_a == "RGBD":
packedAtlas[atlas.name] = np.zeros((atlas_resolution,atlas_resolution, 4), dtype=np.uint8)
if sceneProperties.tlm_encoding_device == "GPU":
if sceneProperties.tlm_encoding_mode_b == "RGBM":
packedAtlas[atlas.name] = np.zeros((atlas_resolution,atlas_resolution, 4), dtype=np.uint8)
if sceneProperties.tlm_encoding_mode_b == "RGBD":
packedAtlas[atlas.name] = np.zeros((atlas_resolution,atlas_resolution, 4), dtype=np.uint8)
if sceneProperties.tlm_encoding_mode_b == "LogLuv":
packedAtlas[atlas.name] = np.zeros((atlas_resolution,atlas_resolution, 4), dtype=np.uint8)
packer[atlas.name].pack()
for idy, rect in enumerate(packer[atlas.name].rect_list()):
print("Packing atlas at: " + str(rect))
aob = rect[5]
src = cv2.imread(os.path.join(lightmap_directory, aob + end + formatEnc), image_channel_depth) #"_baked.hdr"
print("Obj name is: " + aob)
x,y,w,h = rect[1],rect[2],rect[3],rect[4]
print("Obj Shape: " + str(src.shape))
print("Atlas shape: " + str(packedAtlas[atlas.name].shape))
print("Bin Pos: ",x,y,w,h)
packedAtlas[atlas.name][y:h+y, x:w+x] = src
obj = bpy.data.objects[aob]
for idx, layer in enumerate(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 layer.name == uv_channel:
obj.data.uv_layers.active_index = idx
print("UVLayer set to: " + str(obj.data.uv_layers.active_index))
atlasRes = atlas_resolution
texRes = rect[3] #Any dimension w/h (square)
ratio = texRes/atlasRes
scaleUV(obj.data.uv_layers.active, (ratio, ratio), (0,1))
print(rect)
#Postpack error here...
for uv_verts in obj.data.uv_layers.active.data:
#For each vert
#NOTES! => X FUNKER
#TODO => Y
#[0] = bin index
#[1] = x
#[2] = y (? + 1)
#[3] = w
#[4] = h
vertex_x = uv_verts.uv[0] + (rect[1]/atlasRes) #WORKING!
vertex_y = uv_verts.uv[1] - (rect[2]/atlasRes) # + ((rect[2]-rect[4])/atlasRes) # # + (1-((rect[1]-rect[4])/atlasRes))
#tr = "X: {0} + ({1}/{2})".format(uv_verts.uv[0],rect[1],atlasRes)
#print(tr)
#vertex_y = 1 - (uv_verts.uv[1]) uv_verts.uv[1] + (rect[1]/atlasRes)
#SET UV LAYER TO
# atlasRes = atlas_resolution
# texRes = rect[3] #Any dimension w/h (square)
# print(texRes)
# #texRes = 0.0,0.0
# #x,y,w,z = x,y,texRes,texRes
# x,y,w,z = x,y,0,0
# ratio = atlasRes/texRes
# if x == 0:
# x_offset = 0
# else:
# x_offset = 1/(atlasRes/x)
# if y == 0:
# y_offset = 0
# else:
# y_offset = 1/(atlasRes/y)
# vertex_x = (uv_verts.uv[0] * 1/(ratio)) + x_offset
# vertex_y = (1 - ((uv_verts.uv[1] * 1/(ratio)) + y_offset))
#TO FIX:
#SELECT ALL
#Scale Y => -1
uv_verts.uv[0] = vertex_x
uv_verts.uv[1] = vertex_y
#scaleUV(obj.data.uv_layers.active, (1, -1), getBoundsCenter(obj.data.uv_layers.active))
#print(getCenter(obj.data.uv_layers.active))
cv2.imwrite(os.path.join(lightmap_directory, atlas.name + end + formatEnc), packedAtlas[atlas.name])
print("Written: " + str(os.path.join(lightmap_directory, atlas.name + end + formatEnc)))
#Change the material for each material, slot
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:
for slot in obj.material_slots:
nodetree = slot.material.node_tree
for node in nodetree.nodes:
if node.name == "TLM_Lightmap":
existing_image = node.image
atlasImage = bpy.data.images.load(os.path.join(lightmap_directory, atlas.name + end + formatEnc), check_existing=True)
if linear_straight:
if atlasImage.colorspace_settings.name != 'Linear':
atlasImage.colorspace_settings.name = 'Linear'
node.image = atlasImage
#print("Seeking for: " + atlasImage.filepath_raw)
#print(x)
if(os.path.exists(os.path.join(lightmap_directory, obj.name + end + formatEnc))):
os.remove(os.path.join(lightmap_directory, obj.name + end + formatEnc))
existing_image.user_clear()
#Add dilation map here...
for obj in bpy.context.scene.objects:
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
if obj.TLM_ObjectProperties.tlm_postpack_object:
if obj.TLM_ObjectProperties.tlm_postatlas_pointer == atlas.name:
if atlas.tlm_atlas_dilation:
for slot in obj.material_slots:
nodetree = slot.material.node_tree
for node in nodetree.nodes:
if node.name == "TLM_Lightmap":
existing_image = node.image
atlasImage = bpy.data.images.load(os.path.join(lightmap_directory, atlas.name + end + formatEnc), check_existing=True)
img = cv2.imread(atlasImage.filepath_raw, image_channel_depth)
kernel = np.ones((5,5), dtype="float32")
img_dilation = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imshow('Dilation', img_dilation)
cv2.waitKey(0)
print("TODO: Adding dilation for: " + obj.name)
#TODO MASKING OPTION!
else:
print("OpenCV not installed. Skipping postpacking process.")
def getCenter(uv_layer):
total_x, total_y = 0,0
len = 0
for uv_verts in uv_layer.data:
total_x += uv_verts.uv[0]
total_y += uv_verts.uv[1]
len += 1
center_x = total_x / len
center_y = total_y / len
return (center_x, center_y)
def getBoundsCenter(uv_layer):
min_x = getCenter(uv_layer)[0]
max_x = getCenter(uv_layer)[0]
min_y = getCenter(uv_layer)[1]
max_y = getCenter(uv_layer)[1]
len = 0
for uv_verts in uv_layer.data:
if uv_verts.uv[0] < min_x:
min_x = uv_verts.uv[0]
if uv_verts.uv[0] > max_x:
max_x = uv_verts.uv[0]
if uv_verts.uv[1] < min_y:
min_y = uv_verts.uv[1]
if uv_verts.uv[1] > max_y:
max_y = uv_verts.uv[1]
center_x = (max_x - min_x) / 2 + min_x
center_y = (max_y - min_y) / 2 + min_y
return (center_x, center_y)
def scale2D(v, s, p):
return (p[0] + s[0]*(v[0] - p[0]), p[1] + s[1]*(v[1] - p[1]))
def scaleUV( uvMap, scale, pivot ):
for uvIndex in range( len(uvMap.data) ):
uvMap.data[uvIndex].uv = scale2D(uvMap.data[uvIndex].uv, scale, pivot)

Some files were not shown because too many files have changed in this diff Show More