Update Files

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

View File

@ -0,0 +1,124 @@
import bpy
#Todo - Check if already exists, in case multiple objects has the same material
def backup_material_copy(slot):
material = slot.material
dup = material.copy()
dup.name = "." + material.name + "_Original"
dup.use_fake_user = True
def backup_material_cache(slot, path):
bpy.ops.wm.save_as_mainfile(filepath=path, copy=True)
def backup_material_cache_restore(slot, path):
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Restore cache")
# def backup_material_restore(obj): #??
# if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
# print("Restoring material for: " + obj.name)
#Check if object has TLM_PrevMatArray
# if yes
# - check if array.len is bigger than 0:
# if yes:
# for slot in object:
# originalMaterial = TLM_PrevMatArray[index]
#
#
# if no:
# - In which cases are these?
# if no:
# - In which cases are there not?
# - If a lightmapped material was applied to a non-lightmap object?
# if bpy.data.materials[originalMaterial].users > 0: #TODO - Check if all lightmapped
# print("Material has multiple users")
# if originalMaterial in bpy.data.materials:
# slot.material = bpy.data.materials[originalMaterial]
# slot.material.use_fake_user = False
# elif "." + originalMaterial + "_Original" in bpy.data.materials:
# slot.material = bpy.data.materials["." + originalMaterial + "_Original"]
# slot.material.use_fake_user = False
# else:
# print("Material has one user")
# if "." + originalMaterial + "_Original" in bpy.data.materials:
# slot.material = bpy.data.materials["." + originalMaterial + "_Original"]
# slot.material.use_fake_user = False
# elif originalMaterial in bpy.data.materials:
# slot.material = bpy.data.materials[originalMaterial]
# slot.material.use_fake_user = False
def backup_material_restore(obj): #??
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Restoring material for: " + obj.name)
if "TLM_PrevMatArray" in obj:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Material restore array found: " + str(obj["TLM_PrevMatArray"]))
#Running through the slots
prevMatArray = obj["TLM_PrevMatArray"]
slotsLength = len(prevMatArray)
if len(prevMatArray) > 0:
for idx, slot in enumerate(obj.material_slots): #For each slot, we get the index
#We only need the index, corresponds to the array index
try:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Attempting to set material")
originalMaterial = prevMatArray[idx]
except IndexError:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Material restore failed - Resetting")
originalMaterial = ""
if slot.material is not None:
#if slot.material.users < 2:
#slot.material.user_clear() #Seems to be bad; See: https://developer.blender.org/T49837
#bpy.data.materials.remove(slot.material)
if "." + originalMaterial + "_Original" in bpy.data.materials:
slot.material = bpy.data.materials["." + originalMaterial + "_Original"]
slot.material.use_fake_user = False
else:
print("No previous material for " + obj.name)
else:
print("No previous material for " + obj.name)
def backup_material_rename(obj): #??
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Renaming material for: " + obj.name)
if "TLM_PrevMatArray" in obj:
for slot in obj.material_slots:
if slot.material is not None:
if slot.material.name.endswith("_Original"):
newname = slot.material.name[1:-9]
if newname in bpy.data.materials:
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
print("Removing material: " + bpy.data.materials[newname].name)
#if bpy.data.materials[newname].users < 2:
#bpy.data.materials.remove(bpy.data.materials[newname]) #TODO - Maybe remove this
slot.material.name = newname
del obj["TLM_PrevMatArray"]
else:
print("No Previous material array for: " + obj.name)

View File

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

View File

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

View File

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