forked from LeenkxTeam/LNXSDK
354 lines
13 KiB
Python
354 lines
13 KiB
Python
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) |