first commit

This commit is contained in:
Michel Fedde 2024-01-29 21:11:49 +01:00
commit 73df699a09
8 changed files with 482 additions and 0 deletions

160
.gitignore vendored Normal file
View file

@ -0,0 +1,160 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

42
__init__.py Normal file
View file

@ -0,0 +1,42 @@
import bpy
from . panels.panel_options import BakeToIDOptionsPanel
from . panels.panel_advanced import BakeToIDAdvancedMenu
from . operators.bake_to_id_map import BakeToIDMapOperator
from . panels.panel import BakeToIDMapPanel
from . panels.panel_info import BakeToIDInfoPanel
from . properties.bake_to_id import BakeToIDProperties
bl_info = {
"name": "Bake to ID Map",
"author": "iedSoftworks",
"description": "",
"blender": (2, 80, 0),
"category": "Object"
}
classes = (
BakeToIDMapOperator,
BakeToIDMapPanel,
BakeToIDInfoPanel,
BakeToIDOptionsPanel,
BakeToIDAdvancedMenu,
BakeToIDProperties,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
setattr(bpy.types.Scene, 'bake_to_id_props', bpy.props.PointerProperty(type=BakeToIDProperties))
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
del bpy.types.Scene.bake_to_id_props
if __name__ == "__main__":
register()

123
operators/bake_to_id_map.py Normal file
View file

@ -0,0 +1,123 @@
import colorsys
import math
import bpy
class BakeToIDMapOperator(bpy.types.Operator):
bl_idname = "object.bake_to_id_map"
bl_label = "Bake to ID Map"
def execute(self, context):
old_mode = bpy.context.object.mode
if old_mode != "OBJECT":
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
props = context.scene.bake_to_id_props
self.paint_id_mask(context, props)
if old_mode != "OBJECT":
bpy.ops.object.mode_set(mode=old_mode, toggle=False)
return {'FINISHED'}
@staticmethod
def count_ids(context, props):
count = 0
if props.source == 'MATERIAL_INDEX':
for obj in context.selected_objects:
count += len(obj.material_slots)
return count
def paint_id_mask(self, context, props):
targets = self.get_targets(context, props)
if len(targets) < 1:
return
totalTargets = len(targets)
colors = []
total_hues = props.adv_total_hues
total_satuations = props.adv_total_satuations
total_brightnesses = props.adv_total_brightnesses
satuations_break_point = math.pow(total_brightnesses, total_hues)
for i in range(totalTargets):
h = (i / total_hues) % 1
l = (math.ceil(i / total_hues) % total_brightnesses) / total_brightnesses
s = math.ceil(i / satuations_break_point) / total_satuations
colors.append(colorsys.hls_to_rgb(h, l, s))
self.paint_targets(props, targets, colors)
self.after_painting(context, props)
def get_targets(self, context, props):
if props.source == 'MATERIAL_INDEX':
return self.get_material_targets(context)
return []
def get_material_targets(self, context):
targets = []
for obj in context.selected_objects:
if not obj.material_slots: continue
mesh = obj.data
if len(obj.material_slots) < 2:
targets.append((mesh, mesh.polygons))
continue
polygonMaterials = {}
for poly in mesh.polygons:
if poly.material_index not in polygonMaterials:
polygonMaterials[poly.material_index] = []
polygonMaterials[poly.material_index].append(poly)
for polygons in polygonMaterials.values():
targets.append((mesh, polygons))
return targets
def paint_targets(self, props, targets, colors):
if props.target == 'VERTEX_COLORS':
self.paint_targets_vertex_colors(props, targets, colors)
def paint_targets_vertex_colors(self, props, targets, colors):
sortedTargets = {}
for i in range(len(targets)):
target = targets[i]
obj = target[0]
indecies = target[1]
if obj not in sortedTargets:
sortedTargets[obj] = []
sortedTargets[obj].append((indecies, colors[i]))
layer_name = props.target_vertex_color_attribute_name
for mesh in sortedTargets:
if layer_name in mesh.vertex_colors:
mesh.vertex_colors.remove(mesh.vertex_colors[layer_name])
vertex_color_layer = mesh.vertex_colors.new(name=layer_name)
for (indecies, color) in sortedTargets[mesh]:
for polygon in indecies:
for idx in polygon.loop_indices:
vertex_color_layer.data[idx].color = (color[0], color[1], color[2], 1.0)
def after_painting(self, context, props):
if props.source == 'MATERIAL_INDEX':
self.after_painting_source_material_index(props, context)
return
def after_painting_source_material_index(self, props, context):
if props.source_materials_remove_all:
for obj in context.selected_objects:
obj.data.materials.clear()

16
panels/panel.py Normal file
View file

@ -0,0 +1,16 @@
import bpy
class BakeToIDMapPanel(bpy.types.Panel):
bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS"
bl_label = "Bake to ID Map"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Tool"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
self.layout.operator("object.bake_to_id_map", text="Bake")

24
panels/panel_advanced.py Normal file
View file

@ -0,0 +1,24 @@
import math
import bpy
class BakeToIDAdvancedMenu(bpy.types.Panel):
bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_ADVANCED"
bl_parent_id = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS"
bl_label = "Advanced"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Tool"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
props = context.scene.bake_to_id_props
layout.label(text="Colors")
layout.prop(props, "adv_total_hues")
layout.prop(props, "adv_total_satuations")
layout.prop(props, "adv_total_brightnesses")
layout.label(text="Max ID-count: " + str(
math.pow(math.pow(props.adv_total_hues, props.adv_total_satuations), props.adv_total_brightnesses)))

20
panels/panel_info.py Normal file
View file

@ -0,0 +1,20 @@
import bpy
from .. operators.bake_to_id_map import BakeToIDMapOperator
class BakeToIDInfoPanel(bpy.types.Panel):
bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_INFO"
bl_parent_id = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS"
bl_label = "Infos"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Tool"
def draw(self, context):
layout = self.layout
props = context.scene.bake_to_id_props
layout.label(text="Selected Object-Count: " + str(len(context.selected_objects)))
layout.label(text="Estimated ID-Count: " + str(BakeToIDMapOperator.count_ids(context, props)))

45
panels/panel_options.py Normal file
View file

@ -0,0 +1,45 @@
import bpy
class BakeToIDOptionsPanel(bpy.types.Panel):
bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_OPTIONS"
bl_parent_id = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS"
bl_label = "Options"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Tool"
def draw(self, context):
layout = self.layout
props = context.scene.bake_to_id_props
layout.prop(props, "source")
source_settings_box = layout.box()
source_settings = self.get_source_settings(props)
for setting in source_settings:
source_settings_box.prop(props, setting)
layout.separator()
layout.prop(props, "target")
target_settings_box = layout.box()
target_settings = self.get_target_settings(props)
for setting in target_settings:
target_settings_box.prop(props, setting)
def get_source_settings(self, props):
if props.source == 'MATERIAL_INDEX':
return [
'source_materials_remove_all'
]
return []
def get_target_settings(self, props):
if props.target == 'VERTEX_COLORS':
return [
'target_vertex_color_attribute_name'
]
return []

52
properties/bake_to_id.py Normal file
View file

@ -0,0 +1,52 @@
from bpy.types import (PropertyGroup)
from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty)
class BakeToIDProperties(PropertyGroup):
source: EnumProperty(
items=[
('MATERIAL_INDEX', 'Material Index', "It takes the material index as ID basis", 0)
],
name="Source",
description="From where should the IDs be taken",
default = "MATERIAL_INDEX"
)
target: EnumProperty(
items=[('VERTEX_COLORS', 'Vertex Colors', "It bakes the ID to the vertex colors", 0)],
name="Target",
description="To where should the IDs should be baked to",
default="VERTEX_COLORS"
)
source_materials_remove_all : BoolProperty(
name="Remove all source materials",
default=False,
description="Removes every material except the first one."
)
target_vertex_color_attribute_name: StringProperty(
name="Color Attribute",
default="ID_MASK",
)
adv_total_hues: IntProperty(
name="Total Hues",
default=10,
min=1,
soft_max=360,
)
adv_total_satuations: IntProperty(
name="Total Satuations",
default=10,
min=1,
soft_max=100,
)
adv_total_brightnesses: IntProperty(
name="Total Brightnesses",
default=10,
min=1,
soft_max=100,
)