2025-12-01
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import bpy
|
||||
from . import bake_utilities
|
||||
|
||||
from .. Functions import constants
|
||||
from .. Functions import visibility_functions
|
||||
|
||||
|
||||
def bake_texture(self, selected_objects, bake_settings):
|
||||
parent_operator = self
|
||||
# ----------------------- CREATE INSTANCE --------------------#
|
||||
lightmap_utilities = bake_utilities.BakeUtilities(parent_operator, selected_objects, bake_settings)
|
||||
|
||||
if not lightmap_utilities.checkPBR():
|
||||
return
|
||||
|
||||
# -----------------------SET LIGHTMAP UV--------------------#
|
||||
lightmap_utilities.set_active_uv_to_lightmap()
|
||||
|
||||
# -----------------------SETUP UV'S--------------------#
|
||||
lightmap_utilities.unwrap_selected()
|
||||
|
||||
# -----------------------SETUP ENGINE--------------------#
|
||||
lightmap_utilities.setup_engine()
|
||||
|
||||
# -----------------------SWITCH BACK TO SHOW ORG MATERIAL --------------------#
|
||||
visibility_functions.preview_bake_texture(self,context=bpy.context)
|
||||
|
||||
# ----------------------- CREATE NEW MATERIAL FOR BAKING --------------------#
|
||||
lightmap_utilities.create_bake_material("_AO")
|
||||
|
||||
# -----------------------SETUP NODES--------------------#
|
||||
lightmap_utilities.add_node_setup()
|
||||
|
||||
# ----------------------- BAKING --------------------#
|
||||
if bake_settings.lightmap_bake:
|
||||
lightmap_utilities.save_metal_value()
|
||||
lightmap_utilities.bake(constants.Bake_Passes.lightmap)
|
||||
lightmap_utilities.load_metal_value()
|
||||
lightmap_utilities.add_lightmap_flag()
|
||||
|
||||
if bake_settings.ao_bake:
|
||||
lightmap_utilities.bake(constants.Bake_Passes.ao)
|
||||
|
||||
lightmap_utilities.cleanup()
|
||||
del lightmap_utilities
|
||||
return
|
||||
|
||||
|
||||
def bake_on_plane(self,selected_objects,bake_settings):
|
||||
|
||||
parent_operator = self
|
||||
|
||||
# ----------------------- CREATE INSTANCE --------------------#
|
||||
pbr_utilities = bake_utilities.PbrBakeUtilities(parent_operator,selected_objects,bake_settings)
|
||||
|
||||
# -----------------------SETUP ENGINE--------------------#
|
||||
|
||||
pbr_utilities.setup_engine()
|
||||
|
||||
# ----------------------- BAKE --------------------#
|
||||
|
||||
pbr_utilities.bake_materials_on_object()
|
||||
del pbr_utilities
|
||||
|
||||
return
|
||||
@@ -0,0 +1,588 @@
|
||||
import bpy
|
||||
from bpy.types import ObjectShaderFx
|
||||
import mathutils
|
||||
from .. Functions import node_functions
|
||||
from .. Functions import image_functions
|
||||
from .. Functions import constants
|
||||
from .. Functions import visibility_functions
|
||||
from .. Functions import material_functions
|
||||
|
||||
blender_version = bpy.app.version
|
||||
|
||||
class BakeUtilities():
|
||||
C = bpy.context
|
||||
D = bpy.data
|
||||
O = bpy.ops
|
||||
|
||||
all_materials = None
|
||||
image_texture_nodes = None
|
||||
bake_settings = None
|
||||
bake_image = None
|
||||
render_engine = None
|
||||
selected_objects = None
|
||||
image_size = None
|
||||
parent_operator = None
|
||||
tex_node_name = None
|
||||
|
||||
def __init__(self,parent_operator,selected_objects, bake_settings):
|
||||
self.C = bpy.context
|
||||
self.D = bpy.data
|
||||
self.parent_operator = parent_operator
|
||||
self.render_engine = self.C.scene.render.engine
|
||||
self.selected_objects = selected_objects
|
||||
self.all_materials = self.D.materials
|
||||
self.selected_materials = material_functions.get_selected_materials(self.selected_objects)
|
||||
self.bake_settings = bake_settings
|
||||
self.baked_images = []
|
||||
self.image_texture_nodes = set()
|
||||
self.image_size = [int(self.C.scene.img_bake_size),
|
||||
int(self.C.scene.img_bake_size)]
|
||||
image_name = bake_settings.bake_image_name
|
||||
|
||||
self.bake_image = image_functions.create_image(image_name, self.image_size)
|
||||
|
||||
def setup_engine(self):
|
||||
# setup engine
|
||||
if self.render_engine == 'BLENDER_EEVEE':
|
||||
self.C.scene.render.engine = 'CYCLES'
|
||||
|
||||
# setup device type
|
||||
self.cycles_device_type = self.C.preferences.addons['cycles'].preferences.compute_device_type
|
||||
if self.cycles_device_type == 'OPTIX':
|
||||
self.C.preferences.addons['cycles'].preferences.compute_device_type = 'CUDA'
|
||||
|
||||
# setup samples
|
||||
if self.bake_settings.pbr_bake:
|
||||
self.C.scene.cycles.samples = self.bake_settings.pbr_samples
|
||||
if self.bake_settings.lightmap_bake:
|
||||
self.C.scene.cycles.samples = self.bake_settings.lightmap_samples
|
||||
if self.bake_settings.ao_bake:
|
||||
self.C.scene.cycles.samples = self.bake_settings.ao_samples
|
||||
|
||||
self.C.scene.render.resolution_percentage = 100
|
||||
|
||||
def set_active_uv_to_lightmap(self):
|
||||
bpy.ops.object.set_active_uv(uv_slot=2)
|
||||
|
||||
def checkPBR(self):
|
||||
for material in self.selected_materials:
|
||||
self.active_material = material
|
||||
# check if pbr node exists
|
||||
check_ok = node_functions.check_pbr(self.parent_operator,material)
|
||||
if not check_ok :
|
||||
self.parent_operator.report({'INFO'}, "Material " + material.name + " has no PBR Node !")
|
||||
return check_ok
|
||||
|
||||
def unwrap_selected(self):
|
||||
if self.bake_settings.unwrap:
|
||||
self.O.object.add_uv(uv_name=self.bake_settings.uv_name)
|
||||
|
||||
# apply scale on linked
|
||||
sel_objects = self.C.selected_objects
|
||||
scene_objects = self.D.objects
|
||||
linked_objects = set()
|
||||
|
||||
for sel_obj in sel_objects:
|
||||
for scene_obj in scene_objects:
|
||||
if sel_obj.data.original is scene_obj.data and sel_obj is not scene_obj:
|
||||
linked_objects.add(sel_obj)
|
||||
|
||||
# do not apply transform if linked objects in selection
|
||||
if not len(linked_objects)>0:
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
|
||||
|
||||
self.O.object.mode_set(mode='EDIT')
|
||||
self.O.mesh.reveal()
|
||||
self.O.mesh.select_all(action='SELECT')
|
||||
self.O.uv.smart_project(island_margin=self.bake_settings.unwrap_margin)
|
||||
self.O.object.mode_set(mode='OBJECT')
|
||||
|
||||
def create_bake_material(self,material_name_suffix):
|
||||
|
||||
bake_materials = []
|
||||
selected_materials = []
|
||||
for obj in self.selected_objects:
|
||||
for slot in obj.material_slots:
|
||||
selected_materials.append(slot.material)
|
||||
|
||||
# switch to ao material if we are on org and ao was already baked
|
||||
visibility_functions.switch_baked_material(True,"scene")
|
||||
|
||||
for obj in self.selected_objects:
|
||||
for slot in obj.material_slots:
|
||||
material = slot.material
|
||||
bake_material_name = material.name + material_name_suffix
|
||||
|
||||
# check if material was already baked and continue
|
||||
if material_name_suffix in material.name:
|
||||
bake_materials.append(material)
|
||||
continue
|
||||
|
||||
# if not, copy material or take one out of the previewsly filled bake list
|
||||
else :
|
||||
bake_material = list(filter(lambda material: material.name == bake_material_name, bake_materials))
|
||||
|
||||
if len(bake_material) == 0:
|
||||
bake_material = material.copy()
|
||||
bake_material.name = bake_material_name
|
||||
bake_materials.append(bake_material)
|
||||
slot.material = bake_material
|
||||
|
||||
else:
|
||||
bake_material = bake_material[0]
|
||||
slot.material = bake_material
|
||||
|
||||
index = bake_material.name.find(".")
|
||||
if index == -1:
|
||||
obj.bake_version = ""
|
||||
else:
|
||||
obj.bake_version = bake_material.name[index:]
|
||||
|
||||
material.use_fake_user = True
|
||||
|
||||
|
||||
# remove duplicate entries
|
||||
self.selected_materials = list(set(bake_materials))
|
||||
|
||||
def add_gltf_material_output_node(self, material):
|
||||
nodes = material.node_tree.nodes
|
||||
|
||||
name = "glTF Material Output"
|
||||
gltf_node_group = bpy.data.node_groups.new(name, 'ShaderNodeTree')
|
||||
gltf_node_group.inputs.new("NodeSocketFloat", "Occlusion")
|
||||
thicknessFactor = gltf_node_group.inputs.new("NodeSocketFloat", "Thickness")
|
||||
thicknessFactor.default_value = 0.0
|
||||
gltf_node_group.nodes.new('NodeGroupOutput')
|
||||
gltf_node_group_input = gltf_node_group.nodes.new('NodeGroupInput')
|
||||
specular = gltf_node_group.inputs.new("NodeSocketFloat", "Specular")
|
||||
specular.default_value = 1.0
|
||||
specularColor = gltf_node_group.inputs.new("NodeSocketColor", "Specular Color")
|
||||
specularColor.default_value = [1.0,1.0,1.0,1.0]
|
||||
gltf_node_group_input.location = -200, 0
|
||||
|
||||
|
||||
gltf_settings_node = nodes.get(name)
|
||||
if gltf_settings_node is None:
|
||||
gltf_settings_node = nodes.new('ShaderNodeGroup')
|
||||
gltf_settings_node.name = name
|
||||
gltf_settings_node.node_tree = bpy.data.node_groups[name]
|
||||
|
||||
return gltf_settings_node
|
||||
|
||||
|
||||
|
||||
|
||||
def add_gltf_settings_node(self, material):
|
||||
nodes = material.node_tree.nodes
|
||||
# create group data
|
||||
gltf_settings = bpy.data.node_groups.get('glTF Settings')
|
||||
if gltf_settings is None:
|
||||
bpy.data.node_groups.new('glTF Settings', 'ShaderNodeTree')
|
||||
|
||||
# add group to node tree
|
||||
gltf_settings_node = nodes.get('glTF Settings')
|
||||
if gltf_settings_node is None:
|
||||
gltf_settings_node = nodes.new('ShaderNodeGroup')
|
||||
gltf_settings_node.name = 'glTF Settings'
|
||||
gltf_settings_node.node_tree = bpy.data.node_groups['glTF Settings']
|
||||
|
||||
# create group inputs
|
||||
if gltf_settings_node.inputs.get('Occlusion') is None:
|
||||
gltf_settings_node.inputs.new('NodeSocketFloat','Occlusion')
|
||||
|
||||
return gltf_settings_node
|
||||
|
||||
def add_image_texture_node(self, material):
|
||||
nodes = material.node_tree.nodes
|
||||
|
||||
# add image texture
|
||||
if self.bake_settings.lightmap_bake:
|
||||
self.tex_node_name = self.bake_settings.texture_node_lightmap
|
||||
|
||||
if self.bake_settings.ao_bake:
|
||||
self.tex_node_name = self.bake_settings.texture_node_ao
|
||||
|
||||
image_texture_node = node_functions.add_node(material, constants.Shader_Node_Types.image_texture, self.tex_node_name)
|
||||
image_texture_node.image = self.bake_image
|
||||
self.bake_image.colorspace_settings.name = "Linear FilmLight E-Gamut"
|
||||
nodes.active = image_texture_node
|
||||
|
||||
# save texture nodes and pbr nodes for later
|
||||
self.image_texture_nodes.add(image_texture_node)
|
||||
|
||||
return image_texture_node
|
||||
|
||||
def save_metal_value(self):
|
||||
for material in self.selected_materials:
|
||||
pbr_node = node_functions.get_pbr_node(material)
|
||||
|
||||
# save metal value
|
||||
metallic_value = pbr_node.inputs["Metallic"].default_value
|
||||
pbr_node["original_metallic"] = metallic_value
|
||||
pbr_node.inputs["Metallic"].default_value = 0
|
||||
|
||||
# save metal image
|
||||
if pbr_node.inputs["Metallic"].is_linked:
|
||||
|
||||
# get metal image node, save it in pbr node and remove connection
|
||||
metal_image_node_socket = pbr_node.inputs["Metallic"].links[0].from_socket
|
||||
self.metal_image_node_output = metal_image_node_socket
|
||||
node_functions.remove_link(material,metal_image_node_socket,pbr_node.inputs["Metallic"])
|
||||
|
||||
def load_metal_value(self):
|
||||
for material in self.selected_materials:
|
||||
pbr_node = node_functions.get_pbr_node(material)
|
||||
pbr_node.inputs["Metallic"].default_value = pbr_node["original_metallic"]
|
||||
|
||||
# reconnect metal image
|
||||
if hasattr(self,"metal_image_node_output"):
|
||||
node_functions.make_link(material,self.metal_image_node_output,pbr_node.inputs["Metallic"])
|
||||
|
||||
def add_uv_node(self,material):
|
||||
|
||||
uv_node = node_functions.add_node(material, constants.Shader_Node_Types.uv, "Second_UV")
|
||||
uv_node.uv_map = self.bake_settings.uv_name
|
||||
return uv_node
|
||||
|
||||
def position_gltf_setup_nodes(self,material,uv_node,image_texture_node,gltf_settings_node):
|
||||
nodes = material.node_tree.nodes
|
||||
# uv node
|
||||
pbr_node = node_functions.get_pbr_node(material)
|
||||
pos_offset = mathutils.Vector((-900, 400))
|
||||
loc = pbr_node.location + pos_offset
|
||||
uv_node.location = loc
|
||||
|
||||
# image texture
|
||||
loc = loc + mathutils.Vector((300, 0))
|
||||
image_texture_node.location = loc
|
||||
|
||||
# ao node
|
||||
loc = loc + mathutils.Vector((300, 0))
|
||||
gltf_settings_node.location = loc
|
||||
|
||||
nodes.active = image_texture_node
|
||||
|
||||
def add_node_setup(self):
|
||||
for material in self.selected_materials:
|
||||
# AO
|
||||
if self.bake_settings.ao_bake:
|
||||
uv_node = self.add_uv_node(material)
|
||||
image_texture_node = self.add_image_texture_node(material)
|
||||
|
||||
if blender_version <= (3, 3):
|
||||
gltf_settings_node = self.add_gltf_settings_node(material)
|
||||
else:
|
||||
gltf_settings_node = self.add_gltf_material_output_node(material)
|
||||
|
||||
|
||||
# position
|
||||
self.position_gltf_setup_nodes(material,uv_node,image_texture_node,gltf_settings_node)
|
||||
|
||||
# linking
|
||||
node_functions.make_link(material, uv_node.outputs["UV"],image_texture_node.inputs['Vector'])
|
||||
node_functions.make_link(material, image_texture_node.outputs['Color'], gltf_settings_node.inputs['Occlusion'])
|
||||
|
||||
# LIGHTMAP
|
||||
if self.bake_settings.lightmap_bake:
|
||||
image_texture_node = self.add_image_texture_node(material)
|
||||
uv_node = self.add_uv_node(material)
|
||||
# position
|
||||
image_texture_node.location = mathutils.Vector((-500, 200))
|
||||
uv_node.location = mathutils.Vector((-700, 200))
|
||||
|
||||
# linking
|
||||
node_functions.make_link(material, uv_node.outputs["UV"],image_texture_node.inputs['Vector'])
|
||||
|
||||
def bake(self,bake_type):
|
||||
channels_to_bake = bake_type
|
||||
self.baked_images = []
|
||||
denoise = self.bake_settings.denoise
|
||||
|
||||
# no denoise
|
||||
if not denoise:
|
||||
channel = bake_type[0]
|
||||
image = self.bake_images(self.bake_image,channel,denoise)
|
||||
image_functions.save_image(image,False)
|
||||
return
|
||||
|
||||
# bake channels for denoise
|
||||
for channel in channels_to_bake:
|
||||
image_name = self.bake_image.name + "_" + channel
|
||||
image = image_functions.create_image(image_name,self.bake_image.size)
|
||||
self.change_image_in_nodes(image)
|
||||
baked_channel_image = self.bake_images(image,channel,denoise)
|
||||
image_functions.save_image(image,True)
|
||||
self.baked_images.append(baked_channel_image)
|
||||
|
||||
self.denoise()
|
||||
|
||||
def change_image_in_nodes(self,image):
|
||||
for image_texture_node in self.image_texture_nodes:
|
||||
if image_texture_node.name == self.tex_node_name:
|
||||
image_texture_node.image = image
|
||||
|
||||
def bake_images(self, image, channel,denoise):
|
||||
if channel == "NRM":
|
||||
print("Baking Normal Pass")
|
||||
self.C.scene.cycles.samples = 1
|
||||
self.O.object.bake(type="NORMAL", use_clear=self.bake_settings.bake_image_clear, margin=self.bake_settings.bake_margin)
|
||||
|
||||
if channel == "COLOR":
|
||||
print("Baking Color Pass")
|
||||
self.C.scene.cycles.samples = 1
|
||||
self.O.object.bake(type="DIFFUSE", pass_filter={'COLOR'}, use_clear=self.bake_settings.bake_image_clear, margin=self.bake_settings.bake_margin)
|
||||
|
||||
if channel == "AO":
|
||||
if not denoise:
|
||||
self.O.object.bake('INVOKE_DEFAULT',type="AO", use_clear=self.bake_settings.bake_image_clear, margin=self.bake_settings.bake_margin)
|
||||
else:
|
||||
self.O.object.bake(type="AO", use_clear=self.bake_settings.bake_image_clear, margin=self.bake_settings.bake_margin)
|
||||
|
||||
if channel == "NOISY":
|
||||
print("Baking Diffuse Pass")
|
||||
if not denoise:
|
||||
self.O.object.bake('INVOKE_DEFAULT',type="DIFFUSE", pass_filter={'DIRECT', 'INDIRECT'}, use_clear=self.bake_settings.bake_image_clear, margin=self.bake_settings.bake_margin)
|
||||
else:
|
||||
self.O.object.bake(type="DIFFUSE", pass_filter={'DIRECT', 'INDIRECT'}, use_clear=self.bake_settings.bake_image_clear, margin=self.bake_settings.bake_margin)
|
||||
|
||||
return image
|
||||
|
||||
def denoise(self):
|
||||
# denoise
|
||||
if self.bake_settings.lightmap_bake:
|
||||
denoised_image_path = node_functions.comp_ai_denoise(self.baked_images[0],self.baked_images[1],self.baked_images[2])
|
||||
|
||||
self.bake_image.filepath = denoised_image_path
|
||||
self.bake_image.source = "FILE"
|
||||
|
||||
self.change_image_in_nodes(self.bake_image)
|
||||
|
||||
# blur
|
||||
if self.bake_settings.ao_bake and self.bake_settings.denoise:
|
||||
blur_image_path = node_functions.blur_bake_image(self.baked_images[0],self.baked_images[1])
|
||||
self.bake_image.filepath = blur_image_path
|
||||
self.bake_image.source = "FILE"
|
||||
self.change_image_in_nodes(self.bake_image)
|
||||
|
||||
def add_lightmap_flag(self):
|
||||
for obj in self.selected_objects:
|
||||
obj.hasLightmap = True
|
||||
|
||||
def cleanup(self):
|
||||
# set back engine
|
||||
# self.C.scene.render.engine = self.render_engine
|
||||
self.C.preferences.addons['cycles'].preferences.compute_device_type = self.cycles_device_type
|
||||
|
||||
# cleanup images
|
||||
if self.bake_settings.cleanup_textures:
|
||||
for img in self.D.images:
|
||||
if self.bake_image.name in img.name and ("_COLOR" in img.name or "_NRM" in img.name or "_NOISY" in img.name) :
|
||||
self.D.images.remove(img)
|
||||
|
||||
# show image
|
||||
visibility_functions.show_image_in_image_editor(self.bake_image)
|
||||
|
||||
|
||||
class PbrBakeUtilities(BakeUtilities):
|
||||
active_material = None
|
||||
parent_operator = None
|
||||
|
||||
def __init__(self,parent_operator,selected_objects, bake_settings):
|
||||
super().__init__(parent_operator,selected_objects,bake_settings)
|
||||
self.selected_materials = material_functions.get_selected_materials(selected_objects)
|
||||
self.parent_operator = parent_operator
|
||||
|
||||
def ready_for_bake(self,material):
|
||||
|
||||
# check if not baked material
|
||||
if "_Bake" in material.name:
|
||||
print("Skipping cause already baked : " + material.name)
|
||||
return False
|
||||
|
||||
print("\n Checking " + material.name + "\n")
|
||||
|
||||
# check if renderer not set to optix
|
||||
self.setup_engine()
|
||||
|
||||
# check if selected to active is on
|
||||
bpy.context.scene.render.bake.use_selected_to_active = False
|
||||
|
||||
# check if pbr node exists
|
||||
check_ok = node_functions.check_pbr(self.parent_operator,material) and node_functions.check_is_org_material(self.parent_operator,material)
|
||||
if not check_ok :
|
||||
self.parent_operator.report({'INFO'}, "Material " + material.name + " has no PBR Node !")
|
||||
return False
|
||||
|
||||
# copy texture nodes if they are linked multiple times
|
||||
nodes = material.node_tree.nodes
|
||||
image_textrure_nodes = node_functions.get_nodes_by_type(nodes,constants.Node_Types.image_texture)
|
||||
for image_texture_node in image_textrure_nodes:
|
||||
node_functions.remove_double_linking(material,image_texture_node)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def bake_materials_on_object(self):
|
||||
for material in self.selected_materials:
|
||||
self.active_material = material
|
||||
if not (self.ready_for_bake(material)):
|
||||
continue
|
||||
self.add_bake_plane()
|
||||
self.bake_pbr()
|
||||
self.create_pbr_bake_material("_Bake")
|
||||
self.create_nodes_after_pbr_bake()
|
||||
self.cleanup_nodes()
|
||||
|
||||
visibility_functions.switch_baked_material(True,"visible")
|
||||
|
||||
def add_bake_plane(self):
|
||||
material = self.active_material
|
||||
bake_plane = self.D.objects.get(material.name + "_Bake")
|
||||
|
||||
if bake_plane is not None:
|
||||
self.parent_operator.report({'INFO'}, 'Delete Bake Plane')
|
||||
return
|
||||
|
||||
self.O.mesh.primitive_plane_add(size=2, location=(2, 0, 0))
|
||||
bake_plane = self.C.object
|
||||
bake_plane.name = material.name + "_Bake"
|
||||
bake_plane.data.materials.append(material)
|
||||
|
||||
|
||||
def bake_pbr(self):
|
||||
material = self.active_material
|
||||
material.use_fake_user = True
|
||||
|
||||
nodes = material.node_tree.nodes
|
||||
pbr_node = node_functions.get_pbr_node(material)
|
||||
pbr_inputs = node_functions.get_pbr_inputs(pbr_node)
|
||||
image_texture_node = None
|
||||
|
||||
# mute texture mapping
|
||||
if self.bake_settings.mute_texture_nodes:
|
||||
node_functions.mute_all_texture_mappings(material, True)
|
||||
|
||||
for pbr_input in pbr_inputs.values():
|
||||
|
||||
# -----------------------TESTING--------------------#
|
||||
# skip if input has no connection
|
||||
if not pbr_input.is_linked:
|
||||
continue
|
||||
|
||||
# -----------------------IMAGE --------------------#
|
||||
|
||||
image_name = material.name + "_" + pbr_input.name
|
||||
|
||||
# find image
|
||||
bake_image = self.D.images.get(image_name)
|
||||
|
||||
# remove image
|
||||
if bake_image is not None:
|
||||
self.D.images.remove(bake_image)
|
||||
|
||||
bake_image = self.D.images.new(image_name, width=self.image_size[0], height=self.image_size[1])
|
||||
bake_image.name = image_name
|
||||
|
||||
image_texture_node = node_functions.add_node(material,constants.Shader_Node_Types.image_texture,"PBR Bake")
|
||||
|
||||
image_texture_node.image = bake_image
|
||||
nodes.active = image_texture_node
|
||||
|
||||
# -----------------------SET COLOR SPACE--------------------#
|
||||
if pbr_input is not pbr_inputs["base_color_input"]:
|
||||
bake_image.colorspace_settings.name = "Non-Color"
|
||||
|
||||
# -----------------------BAKING--------------------#
|
||||
if pbr_input is pbr_inputs["normal_input"]:
|
||||
node_functions.link_pbr_to_output(material, pbr_node)
|
||||
self.O.object.bake(type="NORMAL", use_clear=True)
|
||||
else:
|
||||
node_functions.emission_setup(material, pbr_input.links[0].from_socket)
|
||||
self.O.object.bake(type="EMIT", use_clear=True)
|
||||
|
||||
# unmute texture mappings
|
||||
node_functions.mute_all_texture_mappings(material, False)
|
||||
|
||||
# delete plane
|
||||
self.O.object.delete()
|
||||
|
||||
# cleanup nodes
|
||||
node_functions.remove_node(material,"Emission Bake")
|
||||
node_functions.remove_node(material,"PBR Bake")
|
||||
node_functions.reconnect_PBR(material, pbr_node)
|
||||
|
||||
def create_pbr_bake_material(self,material_name_suffix):
|
||||
|
||||
# -----------------------CREATE MATERIAL--------------------#
|
||||
org_material = self.active_material
|
||||
bake_material_name = org_material.name + material_name_suffix
|
||||
bake_material = bpy.data.materials.get(bake_material_name)
|
||||
|
||||
if bake_material is not None:
|
||||
bpy.data.materials.remove(bake_material)
|
||||
|
||||
# and create new from org. material
|
||||
bake_material = org_material.copy()
|
||||
bake_material.name = bake_material_name
|
||||
self.bake_material = bake_material
|
||||
|
||||
def create_nodes_after_pbr_bake(self):
|
||||
# -----------------------SETUP VARS--------------------#
|
||||
org_material = self.active_material
|
||||
bake_material = self.bake_material
|
||||
nodes = bake_material.node_tree.nodes
|
||||
pbr_node = node_functions.get_pbr_node(bake_material)
|
||||
pbr_inputs = node_functions.get_pbr_inputs(pbr_node)
|
||||
|
||||
for pbr_input in pbr_inputs.values():
|
||||
|
||||
if not pbr_input.is_linked:
|
||||
continue
|
||||
|
||||
# -----------------------REPLACE IMAGE TEXTURES--------------------#
|
||||
first_node_after_input = pbr_input.links[0].from_node
|
||||
tex_node = node_functions.get_node_by_type_recusivly(bake_material,first_node_after_input,constants.Node_Types.image_texture,True)
|
||||
|
||||
bake_image_name = org_material.name + "_" + pbr_input.name
|
||||
bake_image = self.D.images.get(bake_image_name)
|
||||
|
||||
# if no texture node found (baking procedural textures) add new one
|
||||
if tex_node is None:
|
||||
tex_node = node_functions.add_node(bake_material,constants.Shader_Node_Types.image_texture,bake_image_name)
|
||||
|
||||
# keep org image if nothing changed
|
||||
if bake_image is None:
|
||||
org_image = self.D.images.get(tex_node.image.org_image_name)
|
||||
tex_node.image = org_image
|
||||
else:
|
||||
image_functions.save_image(bake_image)
|
||||
tex_node.image = bake_image
|
||||
|
||||
# -----------------------LINKING--------------------#
|
||||
if pbr_input is pbr_inputs["normal_input"]:
|
||||
normal_node = first_node_after_input
|
||||
normal_node.inputs["Strength"].default_value = 1
|
||||
|
||||
|
||||
if normal_node.type == constants.Node_Types.bump_map:
|
||||
bump_node = normal_node
|
||||
normal_node = node_functions.add_node(bake_material,constants.Shader_Node_Types.normal,"Normal from Bump")
|
||||
normal_node.location = bump_node.location
|
||||
nodes.remove(bump_node)
|
||||
|
||||
node_functions.make_link(bake_material, tex_node.outputs[0], normal_node.inputs["Color"])
|
||||
node_functions.make_link(bake_material, normal_node.outputs["Normal"], pbr_input)
|
||||
else:
|
||||
node_functions.make_link(bake_material,tex_node.outputs[0], pbr_input)
|
||||
|
||||
# -----------------------SET COLOR SPACE--------------------#
|
||||
if pbr_input is not pbr_inputs["base_color_input"]:
|
||||
tex_node.image.colorspace_settings.name = "Non-Color"
|
||||
|
||||
self.active_material = bake_material
|
||||
return bake_material
|
||||
|
||||
def cleanup_nodes(self):
|
||||
bake_material = self.active_material
|
||||
node_functions.remove_unused_nodes(bake_material)
|
||||
Reference in New Issue
Block a user