Merge branch 'develop'
This commit is contained in:
commit
8e1b26851b
10 changed files with 166 additions and 115 deletions
|
|
@ -1 +1 @@
|
||||||
1.0.0+build.5
|
1.0.0+build.18
|
||||||
|
|
@ -10,6 +10,7 @@ PROJECT_NAME = "Bake ID Mask"
|
||||||
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
SOURCE_PATH = os.path.join(CURRENT_PATH, "../src")
|
SOURCE_PATH = os.path.join(CURRENT_PATH, "../src")
|
||||||
|
INIT_FILE_PATH = os.path.join(SOURCE_PATH, "__init__.py")
|
||||||
TARGET_PATH = os.path.join(CURRENT_PATH, '../dist')
|
TARGET_PATH = os.path.join(CURRENT_PATH, '../dist')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
@ -22,6 +23,14 @@ if __name__ == "__main__":
|
||||||
versioning.save_version(nextVersion)
|
versioning.save_version(nextVersion)
|
||||||
|
|
||||||
filename = os.path.join(TARGET_PATH, ZIP_FILE_NAME.format(version=nextVersion.__str__()))
|
filename = os.path.join(TARGET_PATH, ZIP_FILE_NAME.format(version=nextVersion.__str__()))
|
||||||
|
original_init_content = ''
|
||||||
|
with open(INIT_FILE_PATH, 'r') as f:
|
||||||
|
original_init_content = f.read()
|
||||||
|
|
||||||
|
version_insert = original_init_content.replace('# !VERSION', '"version": ({}, {}, {}),'.format(nextVersion.major, nextVersion.minor, nextVersion.patch))
|
||||||
|
with open(INIT_FILE_PATH, 'w') as f:
|
||||||
|
f.write(version_insert)
|
||||||
|
|
||||||
with zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) as zip:
|
with zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) as zip:
|
||||||
for (root, dirs, files) in os.walk(SOURCE_PATH):
|
for (root, dirs, files) in os.walk(SOURCE_PATH):
|
||||||
if '__pycache__' in dirs:
|
if '__pycache__' in dirs:
|
||||||
|
|
@ -38,3 +47,6 @@ if __name__ == "__main__":
|
||||||
os.path.join(root, file),
|
os.path.join(root, file),
|
||||||
os.path.join(PROJECT_NAME, relativePath)
|
os.path.join(PROJECT_NAME, relativePath)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
with open(INIT_FILE_PATH, 'w') as f:
|
||||||
|
f.write(original_init_content)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,12 @@
|
||||||
|
bl_info = {
|
||||||
|
"name": "Bake ID Mask",
|
||||||
|
"author": "iedSoftworks",
|
||||||
|
"description": "",
|
||||||
|
# !VERSION
|
||||||
|
"blender": (2, 92, 0),
|
||||||
|
"category": "Object"
|
||||||
|
}
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from . panels.panel_options import BakeToIDOptionsPanel
|
from . panels.panel_options import BakeToIDOptionsPanel
|
||||||
|
|
@ -7,14 +16,6 @@ from . panels.panel import BakeToIDMapPanel
|
||||||
from . panels.panel_info import BakeToIDInfoPanel
|
from . panels.panel_info import BakeToIDInfoPanel
|
||||||
from . properties.bake_to_id import BakeToIDProperties
|
from . properties.bake_to_id import BakeToIDProperties
|
||||||
|
|
||||||
bl_info = {
|
|
||||||
"name": "Bake ID Mask",
|
|
||||||
"author": "iedSoftworks",
|
|
||||||
"description": "",
|
|
||||||
"blender": (2, 80, 0),
|
|
||||||
"category": "Object"
|
|
||||||
}
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
BakeToIDMapOperator,
|
BakeToIDMapOperator,
|
||||||
BakeToIDMapPanel,
|
BakeToIDMapPanel,
|
||||||
|
|
@ -24,13 +25,14 @@ classes = (
|
||||||
BakeToIDProperties,
|
BakeToIDProperties,
|
||||||
)
|
)
|
||||||
|
|
||||||
def register():
|
|
||||||
|
|
||||||
|
def register():
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
|
|
||||||
setattr(bpy.types.Scene, 'bake_to_id_props', bpy.props.PointerProperty(type=BakeToIDProperties))
|
setattr(bpy.types.Scene, 'bake_to_id_props', bpy.props.PointerProperty(type=BakeToIDProperties))
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import math
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
from .. types import (get_source, get_target)
|
||||||
|
|
||||||
|
|
||||||
class BakeToIDMapOperator(bpy.types.Operator):
|
class BakeToIDMapOperator(bpy.types.Operator):
|
||||||
bl_idname = "object.bake_to_id_map"
|
bl_idname = "object.bake_to_id_map"
|
||||||
|
|
@ -22,17 +24,10 @@ class BakeToIDMapOperator(bpy.types.Operator):
|
||||||
|
|
||||||
return {'FINISHED'}
|
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):
|
def paint_id_mask(self, context, props):
|
||||||
targets = self.get_targets(context, props)
|
source = get_source(props.source)
|
||||||
|
|
||||||
|
targets = source.get_targets(context)
|
||||||
|
|
||||||
if len(targets) < 1:
|
if len(targets) < 1:
|
||||||
return
|
return
|
||||||
|
|
@ -53,71 +48,6 @@ class BakeToIDMapOperator(bpy.types.Operator):
|
||||||
|
|
||||||
colors.append(colorsys.hls_to_rgb(h, l, s))
|
colors.append(colorsys.hls_to_rgb(h, l, s))
|
||||||
|
|
||||||
self.paint_targets(props, targets, colors)
|
target = get_target(props.target)
|
||||||
self.after_painting(context, props)
|
target.paint_targets(props, targets, colors)
|
||||||
|
source.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()
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from .. operators.bake_to_id_map import BakeToIDMapOperator
|
from .. operators.bake_to_id_map import BakeToIDMapOperator
|
||||||
|
from ..types import get_source
|
||||||
|
|
||||||
|
|
||||||
class BakeToIDInfoPanel(bpy.types.Panel):
|
class BakeToIDInfoPanel(bpy.types.Panel):
|
||||||
|
|
@ -16,5 +17,7 @@ class BakeToIDInfoPanel(bpy.types.Panel):
|
||||||
|
|
||||||
props = context.scene.bake_to_id_props
|
props = context.scene.bake_to_id_props
|
||||||
|
|
||||||
|
source = get_source(props.source)
|
||||||
|
|
||||||
layout.label(text="Selected Object-Count: " + str(len(context.selected_objects)))
|
layout.label(text="Selected Object-Count: " + str(len(context.selected_objects)))
|
||||||
layout.label(text="Estimated ID-Count: " + str(BakeToIDMapOperator.count_ids(context, props)))
|
layout.label(text="Estimated ID-Count: " + str(source.estimate_ids(context, props)))
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
|
import textwrap
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
from src.types import get_source, get_target
|
||||||
|
|
||||||
|
|
||||||
class BakeToIDOptionsPanel(bpy.types.Panel):
|
class BakeToIDOptionsPanel(bpy.types.Panel):
|
||||||
bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_OPTIONS"
|
bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_OPTIONS"
|
||||||
|
|
@ -15,31 +19,15 @@ class BakeToIDOptionsPanel(bpy.types.Panel):
|
||||||
props = context.scene.bake_to_id_props
|
props = context.scene.bake_to_id_props
|
||||||
|
|
||||||
layout.prop(props, "source")
|
layout.prop(props, "source")
|
||||||
|
source = get_source(props.source)
|
||||||
source_settings_box = layout.box()
|
source_settings_box = layout.box()
|
||||||
source_settings = self.get_source_settings(props)
|
for setting in source.connected_properties:
|
||||||
for setting in source_settings:
|
|
||||||
source_settings_box.prop(props, setting)
|
source_settings_box.prop(props, setting)
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
layout.prop(props, "target")
|
layout.prop(props, "target")
|
||||||
|
target = get_target(props.target)
|
||||||
target_settings_box = layout.box()
|
target_settings_box = layout.box()
|
||||||
target_settings = self.get_target_settings(props)
|
for setting in target.connected_properties:
|
||||||
for setting in target_settings:
|
|
||||||
target_settings_box.prop(props, setting)
|
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 []
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
from bpy.types import (PropertyGroup)
|
from bpy.types import (PropertyGroup)
|
||||||
from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty)
|
from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty)
|
||||||
|
|
||||||
|
from src.types import get_source_enum, get_targets_enum
|
||||||
|
|
||||||
|
|
||||||
class BakeToIDProperties(PropertyGroup):
|
class BakeToIDProperties(PropertyGroup):
|
||||||
source: EnumProperty(
|
source: EnumProperty(
|
||||||
items=[
|
items=get_source_enum(),
|
||||||
('MATERIAL_INDEX', 'Material Index', "It takes the material index as ID basis", 0)
|
|
||||||
],
|
|
||||||
name="Source",
|
name="Source",
|
||||||
description="From where should the IDs be taken",
|
description="From where should the IDs be taken",
|
||||||
default = "MATERIAL_INDEX"
|
default = "MATERIAL_INDEX"
|
||||||
|
|
||||||
)
|
)
|
||||||
target: EnumProperty(
|
target: EnumProperty(
|
||||||
items=[('VERTEX_COLORS', 'Vertex Colors', "It bakes the ID to the vertex colors", 0)],
|
items=get_targets_enum(),
|
||||||
name="Target",
|
name="Target",
|
||||||
description="To where should the IDs should be baked to",
|
description="To where should the IDs should be baked to",
|
||||||
default="VERTEX_COLORS"
|
default=get_targets_enum()[0][0]
|
||||||
)
|
)
|
||||||
|
|
||||||
source_materials_remove_all : BoolProperty(
|
source_materials_remove_all : BoolProperty(
|
||||||
|
|
|
||||||
43
src/types/__init__.py
Normal file
43
src/types/__init__.py
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
from . sources import material_index as source_mat_index
|
||||||
|
|
||||||
|
from . targets import vertex_colors as target_vertex_colors
|
||||||
|
|
||||||
|
_sources = [
|
||||||
|
source_mat_index
|
||||||
|
]
|
||||||
|
|
||||||
|
_targets = [
|
||||||
|
target_vertex_colors
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_source(id):
|
||||||
|
for source in _sources:
|
||||||
|
if source.source_id == id:
|
||||||
|
return source
|
||||||
|
|
||||||
|
raise Exception("Source not found: " + id)
|
||||||
|
|
||||||
|
def get_target(id):
|
||||||
|
for target in _targets:
|
||||||
|
if target.target_id == id:
|
||||||
|
return target
|
||||||
|
|
||||||
|
raise Exception("Target not found: " + id)
|
||||||
|
|
||||||
|
def get_source_enum():
|
||||||
|
enumList = []
|
||||||
|
i = 0
|
||||||
|
for source in _sources:
|
||||||
|
enumList.append((source.source_id, source.name, source.description, i))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return enumList
|
||||||
|
|
||||||
|
def get_targets_enum():
|
||||||
|
enumList = []
|
||||||
|
i = 0
|
||||||
|
for target in _targets:
|
||||||
|
enumList.append((target.target_id, target.name, target.description, i))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return enumList
|
||||||
41
src/types/sources/material_index.py
Normal file
41
src/types/sources/material_index.py
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
source_id = 'MATERIAL_INDEX'
|
||||||
|
name = 'Material Index'
|
||||||
|
description = 'Uses the current material index as basis for ID mask.'
|
||||||
|
|
||||||
|
connected_properties = [
|
||||||
|
'source_materials_remove_all'
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_targets(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 after_painting(context, props):
|
||||||
|
if props.source_materials_remove_all:
|
||||||
|
for obj in context.selected_objects:
|
||||||
|
obj.data.materials.clear()
|
||||||
|
|
||||||
|
def estimate_ids(context, props):
|
||||||
|
count = 0
|
||||||
|
for obj in context.selected_objects:
|
||||||
|
count += len(obj.material_slots)
|
||||||
|
|
||||||
|
return count
|
||||||
32
src/types/targets/vertex_colors.py
Normal file
32
src/types/targets/vertex_colors.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
target_id = 'COLOR_ATTRIBUTE'
|
||||||
|
name = 'Color Attribute / Vertex Color'
|
||||||
|
description = 'Bakes the ID onto a color attribute (previously known as Vertex Color)'
|
||||||
|
|
||||||
|
connected_properties = [
|
||||||
|
'target_vertex_color_attribute_name'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def paint_targets(props, targets, colors):
|
||||||
|
sorted_targets = {}
|
||||||
|
for i in range(len(targets)):
|
||||||
|
target = targets[i]
|
||||||
|
obj = target[0]
|
||||||
|
indecies = target[1]
|
||||||
|
|
||||||
|
if obj not in sorted_targets:
|
||||||
|
sorted_targets[obj] = []
|
||||||
|
|
||||||
|
sorted_targets[obj].append((indecies, colors[i]))
|
||||||
|
|
||||||
|
layer_name = props.target_vertex_color_attribute_name
|
||||||
|
for mesh in sorted_targets:
|
||||||
|
if layer_name in mesh.attributes:
|
||||||
|
mesh.attributes.remove(mesh.attributes[layer_name])
|
||||||
|
|
||||||
|
color_attribute = mesh.attributes.new(name=layer_name, type='FLOAT_COLOR', domain='CORNER')
|
||||||
|
|
||||||
|
for (indecies, color) in sorted_targets[mesh]:
|
||||||
|
for polygon in indecies:
|
||||||
|
for idx in polygon.loop_indices:
|
||||||
|
color_attribute.data[idx].color = (color[0], color[1], color[2], 1.0)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue