Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 95 additions & 72 deletions quickbake/op.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
# import os
import typing

import bpy
from bpy_extras.node_shader_utils import PrincipledBSDFWrapper

if typing.TYPE_CHECKING:
from .properties import QuickBakeToolPropertyGroup
from .properties import MaterialMode, QuickBakeToolPropertyGroup


class RENDER_OT_bake(bpy.types.Operator):
Expand Down Expand Up @@ -81,7 +77,7 @@ def execute(self, context: bpy.types.Context):
props = scene.QuickBakeToolPropertyGroup # type: ignore

# layer name : is data
passes = []
passes: list[tuple[str, bool]] = []
if props.diffuse_enabled:
passes.append(("DIFFUSE", False))
if props.roughness_enabled:
Expand Down Expand Up @@ -151,76 +147,26 @@ def execute(self, context: bpy.types.Context):

self.cleanup_image_nodes(mesh)

# Create Material
mat = bpy.data.materials.get(props.bake_name)
if mat is None:
mat = bpy.data.materials.new(props.bake_name)
mat.use_nodes = True

# Get shader node (create if not exist)
principled_mat = PrincipledBSDFWrapper(mat, is_readonly=False) # pyright: ignore[reportCallIssue]
principled_node = principled_mat.node_principled_bsdf

# Keeping type hints happy
assert mat.node_tree is not None

shader_nodes = mat.node_tree.nodes
links = mat.node_tree.links

# Texture coordinate node for uv map
uv_node = shader_nodes.get("Texture Coordinate")
if uv_node is None:
uv_node = shader_nodes.new(type="ShaderNodeUVMap")
uv_node.location.x = -1100
uv_node.uv_map = uv_layer.name # type: ignore
# Only create images
if props.mat_mode == MaterialMode.IMAGES:
return {"FINISHED"}

# Mapping node for position, scale, rotation
mapping_node = shader_nodes.get("Texture Coordinate")
if mapping_node is None:
mapping_node = shader_nodes.new(type="ShaderNodeMapping")
mapping_node.location.x = -900
mat = self.create_material(props, uv_layer, passes, images)

# Link uv coordinates to mapping node
links.new(uv_node.outputs["UV"], mapping_node.inputs["Vector"])
# Duplicate object and assign material to new
if props.mat_mode == MaterialMode.COPY:
bpy.ops.object.duplicate()
obj.hide_set(True)
# Get new object
obj = context.active_object

for layer, _ in passes:
y = 0
if layer in self.input_order:
y = (self.input_order.index(layer) - 1) * -300
# Keeping type hints happy
assert obj is not None, "Object is None"
assert isinstance(obj.data, bpy.types.Mesh), "Object is not a mesh"

tex_node = mat.node_tree.get(layer)
if tex_node is None:
tex_node = shader_nodes.new(type="ShaderNodeTexImage")
tex_node.location.x = -700
tex_node.location.y = y

tex_node.image = images[layer] # type: ignore
links.new(mapping_node.outputs["Vector"], tex_node.inputs["Vector"])

shader_input = self.layer_input_map.get(layer, "")
if shader_input:
if layer == "NORMAL":
normal_map_node = shader_nodes.get("Normal Map")
if normal_map_node is None:
normal_map_node = shader_nodes.new(type="ShaderNodeNormalMap")
normal_map_node.location.x = -400
normal_map_node.location.y = y

links.new(
tex_node.outputs["Color"], normal_map_node.inputs["Color"]
)
links.new(
normal_map_node.outputs["Normal"],
principled_node.inputs[shader_input],
)

else:
links.new(
tex_node.outputs["Color"], principled_node.inputs[shader_input]
)

# Assign material to object
if props.use_mat:
# Assign or Copy
if props.mat_mode != MaterialMode.CREATE:
obj.data.materials.clear()
obj.active_material = mat

return {"FINISHED"}
Expand Down Expand Up @@ -294,3 +240,80 @@ def cleanup_image_nodes(self, mesh: bpy.types.Mesh):
node = mat.node_tree.get(node_name)
if node is not None:
mat.node_tree.nodes.remove(node)

def create_material(
self,
props: QuickBakeToolPropertyGroup,
uv_layer: bpy.types.MeshUVLoopLayer,
passes: list[tuple[str, bool]],
images: dict,
):
# Create Material
mat = bpy.data.materials.get(props.bake_name)
if mat is None:
mat = bpy.data.materials.new(props.bake_name)
mat.use_nodes = True

# Get shader node (create if not exist)
principled_mat = PrincipledBSDFWrapper(mat, is_readonly=False) # pyright: ignore[reportCallIssue]
principled_node = principled_mat.node_principled_bsdf

# Keeping type hints happy
assert mat.node_tree is not None

shader_nodes = mat.node_tree.nodes
links = mat.node_tree.links

# Texture coordinate node for uv map
uv_node = shader_nodes.get("Texture Coordinate")
if uv_node is None:
uv_node = shader_nodes.new(type="ShaderNodeUVMap")
uv_node.location.x = -1100
uv_node.uv_map = uv_layer.name # type: ignore

# Mapping node for position, scale, rotation
mapping_node = shader_nodes.get("Texture Coordinate")
if mapping_node is None:
mapping_node = shader_nodes.new(type="ShaderNodeMapping")
mapping_node.location.x = -900

# Link uv coordinates to mapping node
links.new(uv_node.outputs["UV"], mapping_node.inputs["Vector"])

for layer, _ in passes:
y = 0
if layer in self.input_order:
y = (self.input_order.index(layer) - 1) * -300

tex_node = mat.node_tree.get(layer)
if tex_node is None:
tex_node = shader_nodes.new(type="ShaderNodeTexImage")
tex_node.location.x = -700
tex_node.location.y = y

tex_node.image = images[layer] # type: ignore
links.new(mapping_node.outputs["Vector"], tex_node.inputs["Vector"])

shader_input = self.layer_input_map.get(layer, "")
if shader_input:
if layer == "NORMAL":
normal_map_node = shader_nodes.get("Normal Map")
if normal_map_node is None:
normal_map_node = shader_nodes.new(type="ShaderNodeNormalMap")
normal_map_node.location.x = -400
normal_map_node.location.y = y

links.new(
tex_node.outputs["Color"], normal_map_node.inputs["Color"]
)
links.new(
normal_map_node.outputs["Normal"],
principled_node.inputs[shader_input],
)

else:
links.new(
tex_node.outputs["Color"], principled_node.inputs[shader_input]
)

return mat
2 changes: 1 addition & 1 deletion quickbake/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def draw(self, context):

layout.prop(props, "bake_name")
layout.prop(props, "bake_size")
layout.prop(props, "use_mat")
layout.prop(props, "mat_mode")
layout.prop(props, "save_img")

row = layout.row()
Expand Down
37 changes: 33 additions & 4 deletions quickbake/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
from enum import StrEnum


class MaterialMode(StrEnum):
IMAGES = "IMAGES"
CREATE = "CREATE"
ASSIGN = "ASSIGN"
COPY = "COPY"


class QuickBakeToolPropertyGroup(bpy.types.PropertyGroup):
# Bake

Expand All @@ -21,10 +28,32 @@ class QuickBakeToolPropertyGroup(bpy.types.PropertyGroup):
step=1024, # not yet implemented
)

use_mat: bpy.props.BoolProperty(
name="Assign Material",
description="Assign new material with baked textures to the selected object",
default=True,
mat_mode: bpy.props.EnumProperty(
name="Mode",
description="What to do with images after baking",
items=[
(
MaterialMode.IMAGES,
"Image Only",
"Only generate images",
),
(
MaterialMode.CREATE,
"Create Material",
"Create a new material with the baked images",
),
(
MaterialMode.ASSIGN,
"Assign material",
"Assign the material to active object",
),
(
MaterialMode.COPY,
"Copy Object",
"Make a copy of the object with baked material assigned",
),
],
default="ASSIGN",
)

save_img: bpy.props.BoolProperty(
Expand Down