first commit
This commit is contained in:
commit
73df699a09
8 changed files with 482 additions and 0 deletions
160
.gitignore
vendored
Normal file
160
.gitignore
vendored
Normal 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
42
__init__.py
Normal 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
123
operators/bake_to_id_map.py
Normal 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
16
panels/panel.py
Normal 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
24
panels/panel_advanced.py
Normal 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
20
panels/panel_info.py
Normal 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
45
panels/panel_options.py
Normal 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
52
properties/bake_to_id.py
Normal 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,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue