-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Started working on lightmapper extension.
- Loading branch information
1 parent
4d8db46
commit ddc1ee2
Showing
6 changed files
with
312 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import importlib | ||
import os | ||
import sys | ||
|
||
script_dir = os.path.dirname(os.path.abspath(__file__)) | ||
sys.path.insert(0, script_dir) | ||
__package__ = os.path.basename(script_dir) | ||
|
||
import lightmapper.__init__ | ||
import lightmapper.lightmapper_properties | ||
import lightmapper.lightmapper_operators | ||
import lightmapper.lightmapper_panel | ||
|
||
# TODO: Make this autoload everything. | ||
importlib.reload(lightmapper.__init__) | ||
importlib.reload(lightmapper.lightmapper_properties) | ||
importlib.reload(lightmapper.lightmapper_operators) | ||
importlib.reload(lightmapper.lightmapper_panel) | ||
|
||
lightmapper.__init__.register() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from . import lightmapper_operators | ||
from . import lightmapper_panel | ||
from . import lightmapper_properties | ||
|
||
print("Running lightmapper/__init__.py") | ||
|
||
def register(): | ||
lightmapper_properties.register() | ||
lightmapper_operators.register() | ||
lightmapper_panel.register() | ||
|
||
def unregister(): | ||
lightmapper_properties.unregister() | ||
lightmapper_operators.unregister() | ||
lightmapper_panel.unregister() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
schema_version = "1.0.0" | ||
|
||
# Example of manifest file for a Blender extension | ||
# Change the values according to your extension | ||
id = "lightmapper" | ||
version = "1.0.0" | ||
name = "Lightmapper" | ||
tagline = "Lightmapper Blender Addon" | ||
maintainer = "Simon Nordon <[email protected]>" | ||
# Supported types: "add-on", "theme" | ||
type = "add-on" | ||
|
||
# Optional link to documentation, support, source files, etc | ||
# Optional link to documentation, support, source files, etc | ||
# website = "https://extensions.blender.org/add-ons/my-example-package/" | ||
|
||
# Optional list defined by Blender and server, see: | ||
# https://docs.blender.org/manual/en/dev/advanced/extensions/tags.html | ||
tags = ["Bake"] | ||
|
||
blender_version_min = "4.2.0" | ||
# # Optional: Blender version that the extension does not support, earlier versions are supported. | ||
# # This can be omitted and defined later on the extensions platform if an issue is found. | ||
# blender_version_max = "5.1.0" | ||
|
||
# License conforming to https://spdx.org/licenses/ (use "SPDX: prefix) | ||
# https://docs.blender.org/manual/en/dev/advanced/extensions/licenses.html | ||
license = [ | ||
"SPDX:GPL-2.0-or-later", | ||
] | ||
# Optional: required by some licenses. | ||
# copyright = [ | ||
# "2002-2024 Developer Name", | ||
# "1998 Company Name", | ||
# ] | ||
|
||
# Optional list of supported platforms. If omitted, the extension will be available in all operating systems. | ||
# platforms = ["windows-x64", "macos-arm64", "linux-x64"] | ||
# Other supported platforms: "windows-arm64", "macos-x64" | ||
|
||
# Optional: bundle 3rd party Python modules. | ||
# https://docs.blender.org/manual/en/dev/advanced/extensions/python_wheels.html | ||
# wheels = [ | ||
# "./wheels/hexdump-3.3-py3-none-any.whl", | ||
# "./wheels/jsmin-3.0.1-py3-none-any.whl", | ||
# ] | ||
|
||
# # Optional: add-ons can list which resources they will require: | ||
# # * files (for access of any filesystem operations) | ||
# # * network (for internet access) | ||
# # * clipboard (to read and/or write the system clipboard) | ||
# # * camera (to capture photos and videos) | ||
# # * microphone (to capture audio) | ||
# # | ||
# # If using network, remember to also check `bpy.app.online_access` | ||
# # https://docs.blender.org/manual/en/dev/advanced/extensions/addons.html#internet-access | ||
# # | ||
# # For each permission it is important to also specify the reason why it is required. | ||
# # Keep this a single short sentence without a period (.) at the end. | ||
# # For longer explanations use the documentation or detail page. | ||
# | ||
# [permissions] | ||
# network = "Need to sync motion-capture data to server" | ||
# files = "Import/export FBX from/to disk" | ||
# clipboard = "Copy and paste bone transforms" | ||
|
||
# Optional: build settings. | ||
# https://docs.blender.org/manual/en/dev/advanced/extensions/command_line_arguments.html#command-line-args-extension-build | ||
# [build] | ||
# paths_exclude_pattern = [ | ||
# "__pycache__/", | ||
# "/.git/", | ||
# "/*.zip", | ||
# ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import bpy | ||
|
||
import bpy.utils | ||
|
||
|
||
|
||
class LIGHTMAPPER_OT_create_lightmap_uv(bpy.types.Operator): | ||
bl_idname = "lightmapper.create_lightmap_uv" | ||
bl_label = "Create Lightmap UV" | ||
bl_description = "Create a second UV channel called 'Lightmap' and select it" | ||
bl_options = {'REGISTER', 'UNDO'} | ||
|
||
def execute(self, context): | ||
mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH'] | ||
|
||
if not mesh_objects: | ||
self.report({'ERROR'}, "No mesh objects selected.") | ||
return {'CANCELLED'} | ||
|
||
for obj in mesh_objects: | ||
uv_layers = obj.data.uv_layers | ||
if len(uv_layers) < 2: | ||
uv_layer = uv_layers.new(name="Lightmap") | ||
uv_layers.active = uv_layer | ||
self.report({'INFO'}, f"Lightmap UV created for {obj.name}.") | ||
else: | ||
self.report({'INFO'}, f"{obj.name} already has a Lightmap UV.") | ||
|
||
# Perform lightmap unwrap | ||
print(f"Performing lightmap unwrap for {obj.name}") | ||
bpy.context.view_layer.objects.active = obj | ||
bpy.ops.uv.lightmap_pack() | ||
|
||
return {'FINISHED'} | ||
|
||
|
||
|
||
|
||
class LIGHTMAPPER_OT_bake_lightmap(bpy.types.Operator): | ||
bl_idname = "lightmapper.bake_lightmap" | ||
bl_label = "Bake Lightmap" | ||
bl_description = "Bake lightmap for selected objects" | ||
bl_options = {'REGISTER', 'UNDO'} | ||
|
||
def check_context(self, context): | ||
""" Ensure the object is in a state that supports baking. """ | ||
mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH'] | ||
# Ensure we're in object mode. | ||
if context.mode != 'OBJECT': | ||
self.report({'ERROR'}, "Lightmap baking requires object mode.") | ||
return False | ||
|
||
# Ensure we have at least one object selected. | ||
if not mesh_objects: | ||
self.report({'ERROR'}, "No mesh objects selected.") | ||
return False | ||
|
||
# Ensure there are no disabled for rendering. | ||
for obj in mesh_objects: | ||
if obj.hide_render or obj.hide_viewport: | ||
self.report({'ERROR'}, f"Object {obj.name} is disabled for rendering or hidden in viewport.") | ||
return False | ||
|
||
# Ensure each mesh has 2 uv channels. | ||
for obj in mesh_objects: | ||
if len(obj.data.uv_layers) < 2: | ||
self.report({'ERROR'}, f"Object {obj.name} does not have a Lightmap channel.") | ||
return False | ||
|
||
return True | ||
|
||
def correct_context(self, context): | ||
""" Change the state of the selected objects to work for baking.""" | ||
mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH'] | ||
|
||
self.report({'INFO'}, "Correcting UV Selections.") | ||
# Ensure that the first UVMap is set to render, and that "Lightmap" UV is selected. | ||
for obj in mesh_objects: | ||
# If the lightmap is renderable, set it to the first UVMap. Otherwise respect user choice. | ||
obj.data.uv_layers[0].active_render = True | ||
# Ensure the lightmap is selected, as that's the UV we're baking to. | ||
obj.data.uv_layers["Lightmap"].active = True | ||
|
||
def execute(self, context): | ||
if not self.check_context(context): | ||
return {'CANCELLED'} | ||
|
||
self.correct_context(context) | ||
|
||
self.report({'INFO'}, "Lightmap baking started.") | ||
return {'FINISHED'} | ||
|
||
for obj in context.selected_objects: | ||
if obj.type == 'MESH': | ||
# Set up lightmap UV if not present | ||
if len(obj.data.uv_layers) < 2: | ||
obj.data.uv_layers.new(name="Lightmap") | ||
|
||
# Set up image for baking | ||
image = bpy.data.images.new(name=f"{obj.name}_Lightmap", width=1024, height=1024) | ||
|
||
# Set up material for baking | ||
material = obj.active_material | ||
if not material: | ||
material = bpy.data.materials.new(name=f"{obj.name}_Lightmap_Material") | ||
obj.data.materials.append(material) | ||
|
||
# Set up node for baking | ||
material.use_nodes = True | ||
node_tree = material.node_tree | ||
texture_node = node_tree.nodes.new('ShaderNodeTexImage') | ||
texture_node.image = image | ||
|
||
# Perform bake | ||
bpy.ops.object.bake(type='COMBINED') | ||
|
||
self.report({'INFO'}, "Lightmap baking completed") | ||
return {'FINISHED'} | ||
|
||
from bpy.utils import register_class, unregister_class | ||
from .lightmapper_properties import LIGHTMAPPER_PT_properties | ||
|
||
def register(): | ||
print("Registering lightmapper_operators") | ||
bpy.utils.register_class(LIGHTMAPPER_OT_create_lightmap_uv) | ||
bpy.utils.register_class(LIGHTMAPPER_OT_bake_lightmap) | ||
|
||
def unregister(): | ||
bpy.utils.unregister_class(LIGHTMAPPER_OT_create_lightmap_uv) | ||
bpy.utils.unregister_class(LIGHTMAPPER_OT_bake_lightmap) | ||
|
||
if __name__ == "__main__": | ||
register() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import bpy | ||
|
||
class LightmapperPanel(bpy.types.Panel): | ||
bl_idname = "OBJECT_PT_lightmapper_panel" | ||
bl_label = "Lightmapper Panel" | ||
bl_description = "This is a lightmapper panel, for starting a new addon." | ||
bl_space_type = "VIEW_3D" | ||
bl_region_type = "UI" | ||
bl_category = "Lightmapper" | ||
bl_order = 0 | ||
|
||
def draw_header(self, context): | ||
layout = self.layout | ||
layout.label(text="", icon="OUTLINER_DATA_LIGHTPROBE") | ||
|
||
def draw(self, context): | ||
layout = self.layout | ||
scene = context.scene | ||
lightmapper_props = scene.lightmapper_properties | ||
|
||
|
||
|
||
layout.operator("lightmapper.create_lightmap_uv") | ||
|
||
|
||
layout.prop(scene.lightmapper_properties, "lightmap_resolution") | ||
layout.prop(scene.lightmapper_properties, "export_path") | ||
layout.operator("lightmapper.bake_lightmap") | ||
|
||
def register(): | ||
bpy.utils.register_class(LightmapperPanel) | ||
|
||
def unregister(): | ||
bpy.utils.unregister_class(LightmapperPanel) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import bpy | ||
from bpy.props import EnumProperty, StringProperty # type: ignore | ||
|
||
class LIGHTMAPPER_PT_properties(bpy.types.PropertyGroup): | ||
lightmap_resolution: EnumProperty( | ||
name="Lightmap Resolution", | ||
description="Choose the resolution for the lightmap", | ||
items=[ | ||
('512', "512", "512x512 pixels"), | ||
('1024', "1k", "1024x1024 pixels"), | ||
('2048', "2k", "2048x2048 pixels"), | ||
('4096', "4k", "4096x4096 pixels"), | ||
('8192', "8k", "8192x8192 pixels"), | ||
], | ||
default='2048' | ||
) # type: ignore | ||
|
||
export_path: StringProperty( | ||
name="Export Path", | ||
description="Path to export the lightmap", | ||
default="", | ||
maxlen=1024, | ||
subtype='DIR_PATH' | ||
) # type: ignore | ||
|
||
def register(): | ||
print("Registering lightmapper_properties") | ||
bpy.utils.register_class(LIGHTMAPPER_PT_properties) | ||
bpy.types.Scene.lightmapper_properties = bpy.props.PointerProperty(type=LIGHTMAPPER_PT_properties) | ||
|
||
def unregister(): | ||
del bpy.types.Scene.lightmapper_properties | ||
bpy.utils.unregister_class(LIGHTMAPPER_PT_properties) |