forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
1
leenkx/blender/lnx/lightmapper/__init__.py
Normal file
1
leenkx/blender/lnx/lightmapper/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__all__ = ('Operators', 'Panels', 'Properties', 'Preferences', 'Utility', 'Keymap')
|
Binary file not shown.
BIN
leenkx/blender/lnx/lightmapper/assets/TLM_Overlay.png
Normal file
BIN
leenkx/blender/lnx/lightmapper/assets/TLM_Overlay.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
BIN
leenkx/blender/lnx/lightmapper/assets/dash.ogg
Normal file
BIN
leenkx/blender/lnx/lightmapper/assets/dash.ogg
Normal file
Binary file not shown.
BIN
leenkx/blender/lnx/lightmapper/assets/gentle.ogg
Normal file
BIN
leenkx/blender/lnx/lightmapper/assets/gentle.ogg
Normal file
Binary file not shown.
BIN
leenkx/blender/lnx/lightmapper/assets/noot.ogg
Normal file
BIN
leenkx/blender/lnx/lightmapper/assets/noot.ogg
Normal file
Binary file not shown.
BIN
leenkx/blender/lnx/lightmapper/assets/pingping.ogg
Normal file
BIN
leenkx/blender/lnx/lightmapper/assets/pingping.ogg
Normal file
Binary file not shown.
BIN
leenkx/blender/lnx/lightmapper/assets/sound.ogg
Normal file
BIN
leenkx/blender/lnx/lightmapper/assets/sound.ogg
Normal file
Binary file not shown.
BIN
leenkx/blender/lnx/lightmapper/assets/tlm_data.blend
Normal file
BIN
leenkx/blender/lnx/lightmapper/assets/tlm_data.blend
Normal file
Binary file not shown.
BIN
leenkx/blender/lnx/lightmapper/icons/bake.png
Normal file
BIN
leenkx/blender/lnx/lightmapper/icons/bake.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
BIN
leenkx/blender/lnx/lightmapper/icons/clean.png
Normal file
BIN
leenkx/blender/lnx/lightmapper/icons/clean.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
BIN
leenkx/blender/lnx/lightmapper/icons/explore.png
Normal file
BIN
leenkx/blender/lnx/lightmapper/icons/explore.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
7
leenkx/blender/lnx/lightmapper/keymap/__init__.py
Normal file
7
leenkx/blender/lnx/lightmapper/keymap/__init__.py
Normal file
@ -0,0 +1,7 @@
|
||||
from . import keymap
|
||||
|
||||
def register():
|
||||
keymap.register()
|
||||
|
||||
def unregister():
|
||||
keymap.unregister()
|
22
leenkx/blender/lnx/lightmapper/keymap/keymap.py
Normal file
22
leenkx/blender/lnx/lightmapper/keymap/keymap.py
Normal 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[:]
|
Binary file not shown.
Binary file not shown.
27
leenkx/blender/lnx/lightmapper/network/client.py
Normal file
27
leenkx/blender/lnx/lightmapper/network/client.py
Normal 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()
|
71
leenkx/blender/lnx/lightmapper/network/server.py
Normal file
71
leenkx/blender/lnx/lightmapper/network/server.py
Normal 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.")
|
50
leenkx/blender/lnx/lightmapper/operators/__init__.py
Normal file
50
leenkx/blender/lnx/lightmapper/operators/__init__.py
Normal 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)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
193
leenkx/blender/lnx/lightmapper/operators/imagetools.py
Normal file
193
leenkx/blender/lnx/lightmapper/operators/imagetools.py
Normal 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'}
|
81
leenkx/blender/lnx/lightmapper/operators/installopencv.py
Normal file
81
leenkx/blender/lnx/lightmapper/operators/installopencv.py
Normal 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'}
|
1731
leenkx/blender/lnx/lightmapper/operators/tlm.py
Normal file
1731
leenkx/blender/lnx/lightmapper/operators/tlm.py
Normal file
File diff suppressed because it is too large
Load Diff
0
leenkx/blender/lnx/lightmapper/panels/__init__.py
Normal file
0
leenkx/blender/lnx/lightmapper/panels/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
66
leenkx/blender/lnx/lightmapper/panels/image.py
Normal file
66
leenkx/blender/lnx/lightmapper/panels/image.py
Normal 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")
|
17
leenkx/blender/lnx/lightmapper/panels/light.py
Normal file
17
leenkx/blender/lnx/lightmapper/panels/light.py
Normal 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
|
126
leenkx/blender/lnx/lightmapper/panels/object.py
Normal file
126
leenkx/blender/lnx/lightmapper/panels/object.py
Normal 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")
|
756
leenkx/blender/lnx/lightmapper/panels/scene.py
Normal file
756
leenkx/blender/lnx/lightmapper/panels/scene.py
Normal 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")
|
17
leenkx/blender/lnx/lightmapper/panels/world.py
Normal file
17
leenkx/blender/lnx/lightmapper/panels/world.py
Normal 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
|
16
leenkx/blender/lnx/lightmapper/preferences/__init__.py
Normal file
16
leenkx/blender/lnx/lightmapper/preferences/__init__.py
Normal 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)
|
106
leenkx/blender/lnx/lightmapper/preferences/addon_preferences.py
Normal file
106
leenkx/blender/lnx/lightmapper/preferences/addon_preferences.py
Normal 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")
|
62
leenkx/blender/lnx/lightmapper/properties/__init__.py
Normal file
62
leenkx/blender/lnx/lightmapper/properties/__init__.py
Normal 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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
166
leenkx/blender/lnx/lightmapper/properties/atlas.py
Normal file
166
leenkx/blender/lnx/lightmapper/properties/atlas.py
Normal 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)
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,4 @@
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
|
||||
class TLM_IntegratedDenoiseEngineProperties(bpy.types.PropertyGroup):
|
40
leenkx/blender/lnx/lightmapper/properties/denoiser/oidn.py
Normal file
40
leenkx/blender/lnx/lightmapper/properties/denoiser/oidn.py
Normal 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")
|
21
leenkx/blender/lnx/lightmapper/properties/denoiser/optix.py
Normal file
21
leenkx/blender/lnx/lightmapper/properties/denoiser/optix.py
Normal 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.")
|
4
leenkx/blender/lnx/lightmapper/properties/filtering.py
Normal file
4
leenkx/blender/lnx/lightmapper/properties/filtering.py
Normal file
@ -0,0 +1,4 @@
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
|
||||
class TLM_FilteringProperties(bpy.types.PropertyGroup):
|
26
leenkx/blender/lnx/lightmapper/properties/image.py
Normal file
26
leenkx/blender/lnx/lightmapper/properties/image.py
Normal 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)
|
182
leenkx/blender/lnx/lightmapper/properties/object.py
Normal file
182
leenkx/blender/lnx/lightmapper/properties/object.py
Normal 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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
115
leenkx/blender/lnx/lightmapper/properties/renderer/cycles.py
Normal file
115
leenkx/blender/lnx/lightmapper/properties/renderer/cycles.py
Normal 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)
|
@ -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")
|
@ -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")
|
585
leenkx/blender/lnx/lightmapper/properties/scene.py
Normal file
585
leenkx/blender/lnx/lightmapper/properties/scene.py
Normal 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)
|
0
leenkx/blender/lnx/lightmapper/utility/__init__.py
Normal file
0
leenkx/blender/lnx/lightmapper/utility/__init__.py
Normal file
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.
1361
leenkx/blender/lnx/lightmapper/utility/build.py
Normal file
1361
leenkx/blender/lnx/lightmapper/utility/build.py
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
0
leenkx/blender/lnx/lightmapper/utility/cycles/ao.py
Normal file
0
leenkx/blender/lnx/lightmapper/utility/cycles/ao.py
Normal file
124
leenkx/blender/lnx/lightmapper/utility/cycles/cache.py
Normal file
124
leenkx/blender/lnx/lightmapper/utility/cycles/cache.py
Normal 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)
|
179
leenkx/blender/lnx/lightmapper/utility/cycles/lightmap.py
Normal file
179
leenkx/blender/lnx/lightmapper/utility/cycles/lightmap.py
Normal 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()
|
527
leenkx/blender/lnx/lightmapper/utility/cycles/nodes.py
Normal file
527
leenkx/blender/lnx/lightmapper/utility/cycles/nodes.py
Normal 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
|
947
leenkx/blender/lnx/lightmapper/utility/cycles/prepare.py
Normal file
947
leenkx/blender/lnx/lightmapper/utility/cycles/prepare.py
Normal 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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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)
|
207
leenkx/blender/lnx/lightmapper/utility/denoiser/oidn.py
Normal file
207
leenkx/blender/lnx/lightmapper/utility/denoiser/oidn.py
Normal 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))
|
92
leenkx/blender/lnx/lightmapper/utility/denoiser/optix.py
Normal file
92
leenkx/blender/lnx/lightmapper/utility/denoiser/optix.py
Normal 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
|
674
leenkx/blender/lnx/lightmapper/utility/encoding.py
Normal file
674
leenkx/blender/lnx/lightmapper/utility/encoding.py
Normal 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()
|
Binary file not shown.
49
leenkx/blender/lnx/lightmapper/utility/filtering/numpy.py
Normal file
49
leenkx/blender/lnx/lightmapper/utility/filtering/numpy.py
Normal 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)
|
178
leenkx/blender/lnx/lightmapper/utility/filtering/opencv.py
Normal file
178
leenkx/blender/lnx/lightmapper/utility/filtering/opencv.py
Normal 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)
|
160
leenkx/blender/lnx/lightmapper/utility/filtering/shader.py
Normal file
160
leenkx/blender/lnx/lightmapper/utility/filtering/shader.py
Normal 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)
|
77
leenkx/blender/lnx/lightmapper/utility/gui/Viewport.py
Normal file
77
leenkx/blender/lnx/lightmapper/utility/gui/Viewport.py
Normal 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')
|
Binary file not shown.
31
leenkx/blender/lnx/lightmapper/utility/icon.py
Normal file
31
leenkx/blender/lnx/lightmapper/utility/icon.py
Normal 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)
|
21
leenkx/blender/lnx/lightmapper/utility/log.py
Normal file
21
leenkx/blender/lnx/lightmapper/utility/log.py
Normal 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)
|
Binary file not shown.
259
leenkx/blender/lnx/lightmapper/utility/luxcore/setup.py
Normal file
259
leenkx/blender/lnx/lightmapper/utility/luxcore/setup.py
Normal 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"
|
||||
"""
|
Binary file not shown.
Binary file not shown.
243
leenkx/blender/lnx/lightmapper/utility/octane/configure.py
Normal file
243
leenkx/blender/lnx/lightmapper/utility/octane/configure.py
Normal 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]
|
||||
]
|
71
leenkx/blender/lnx/lightmapper/utility/octane/lightmap2.py
Normal file
71
leenkx/blender/lnx/lightmapper/utility/octane/lightmap2.py
Normal 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!")
|
354
leenkx/blender/lnx/lightmapper/utility/pack.py
Normal file
354
leenkx/blender/lnx/lightmapper/utility/pack.py
Normal 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
Reference in New Issue
Block a user